ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】CF1559E Mocha and Stars

2021-08-19 14:00:45  阅读:170  来源: 互联网

标签:... frac int 题解 sum CF1559E Stars mathcal 复杂度


题目:Codeforces 链接  &  Luogu 链接

如果只看前两个条件,那么这是一个比较显然的背包问题。

令 $f_{i,j}$ 表示前 $n$ 个数 $a_i$ 总和为 $j$ 的方案数。

那么对于每个 $a_i=l_i \sim r_i$ 均有

$$f_{i,j}=\sum_{k=l_i}^{r_i} f_{i-1,j-k}$$

当然直接上背包复杂度是 $\mathcal{O}(nm^2)$ 级别的,我们需要把每一个 $i$ 的所有 $f_{i,j}$ 记录一个前缀和。记

$$s_{i,j}=\sum_{k=0}^{j}f_{i,k}$$

且当 $j<0$ 时 $s_{i,j}=0$。

那么有可以一次性转移的方程:

$$f_{i,j}=s_{i-1,j-l_i}-s_{i-1,j-r_i-1}$$

时间复杂度降为了 $\mathcal{O}(nm)$。


之后就是最后一个条件:$\gcd(a_1,a_2,...,a_n)=1$。

这可以让人联想到许多数论题目的常见解决办法,比如莫比乌斯反演或者容斥,这里讲讲容斥做法。

$$F(x)=\sum_{a_1=l_1}^{r_1}\sum_{a_2=l_2}^{r_2}...\sum_{a_n=l_n}^{r_n}[\gcd(a_1,a_2,...,a_n)=x]\left[\sum_{i}a_i \le m\right]$$

显然我们最后要求 $F(1)$。

观察到这个式子仍比较麻烦,但是条件转化成 $[x \mid \gcd(a_1,a_2,...,a_n)]$ 的话问题就会好做点。

于是再定义 $G(x)=\sum\limits_{d=1}^{\lfloor\frac{m}{x}\rfloor}F(dx)$,相当于

$$G(x)=\sum_{a_1=l_1}^{r_1}\sum_{a_2=l_2}^{r_2}...\sum_{a_n=l_n}^{r_n}[x \mid \gcd(a_1,a_2,...,a_n)]\left[\sum_{i}a_i \le m\right]$$

然后 $[x \mid \gcd(a_1,a_2,...,a_n)]$ 这个条件就等价于限制了每个 $a_i$ 都是 $x$ 的倍数

那我们在枚举 $a_i$ 的时候直接强制它是 $x$ 的倍数,就消去 $\gcd=1$ 的条件,可以直接上背包了。


之后还没完,我们要算的是 $F(1)$,但只求出了 $G(x)$。

观察一下 $G(x)$ 的定义式

$$G(x)=\sum_{d=1}^{\lfloor\frac{m}{x}\rfloor}F(dx)$$

移个项:

$$F(x)=G(x)-\sum_{d=2}^{\lfloor\frac{m}{x}\rfloor}F(dx)$$

那么我们从 $m$ 到 $1$ 倒序枚举 $x$,$G(x)$ 用背包求,且所有的 $F(x)$ 都可以求出来。

在枚举 $x$ 和 $x$ 的倍数这一步骤,时间复杂度为调和级数级别的,大约为 $\mathcal{O}(m \ln m)$。

因此均摊到每个 $x$ 的时间复杂度为 $\mathcal{O}(\ln m)$

对于每个 $G(x)$,我们可以用背包求。枚举 $x$ 的倍数也不怎么方便,所以我们可以将上下界以及 $m$ 都除掉 $x$,这样就可以使得 $a_i$ 连续,且减小背包容量,优化时间复杂度。

对于每个 $G(x)$,背包容量可以降为 $\lfloor\frac{m}{x}\rfloor$。

上文说了,$\sum\limits_{i=1}^m\frac{m}{x}=\mathcal{O}(m \ln m)$。

因此该做法总复杂度为 $\mathcal{O}(nm \ln m)$。

说一下写代码时的注意点:

  • 前缀和数组的初始值为 $0$。
  • 注意方式背包时下标变负数的情况。
  • 做除法的时候,注意下界 $\frac{l_i}{x}$ 要上取整。
  • 取模要取干净。

这道题就这么做完了。具体细节可以看代码:

#include <bits/stdc++.h>
#define N 100010
#define MOD 998244353
#define reg register
typedef long long ll;
using namespace std;
 
int n, m, l[N], r[N], dp[N], las[N], ss[N], ans, sss, slas[N];
 
inline int F(int x, int y){        // 上取整
    return x / y + (x % y != 0);
}
 
int main(){
 
    cin >> n >> m;
    for(reg int i = 1; i <= n; i++) cin >> l[i] >> r[i];
    for(reg int d = m; d >= 1; d--){
        for(reg int j = 0; j <= m / d; j++)
            dp[j] = 0, las[j] = 0, slas[j] = 0;
        las[0] = slas[0] = 1;
        for(reg int j = 1; j <= m / d; j++)
            slas[j] = (slas[j - 1] + las[j]);
        for(reg int j = 1; j <= n; j++){
            for(reg int L = m / d; L >= F(l[j], d); L--){
                if(L - r[j] / d > 0) dp[L] = (slas[L - F(l[j], d)] - slas[L - r[j] / d - 1] + MOD) % MOD;
                else dp[L] = slas[L - F(l[j], d)];
            }
            for(reg int j = 0; j <= m / d; j++)
                las[j] = dp[j], dp[j] = 0;
            slas[0] = las[0];
            for(reg int j = 1; j <= m / d; j++)
                slas[j] = (slas[j - 1] + las[j]) % MOD;
        }
        for(reg int j = 0; j <= m / d; j++)
            ss[d] = (ss[d] + las[j]) % MOD;
        for(reg int j = d + d; j <= m; j += d)
            ss[d] = (ss[d] - ss[j] + MOD) % MOD;
    }
    printf("%d\n", ss[1]);
 
    return 0;
}

 

标签:...,frac,int,题解,sum,CF1559E,Stars,mathcal,复杂度
来源: https://www.cnblogs.com/zengpeichen/p/15161411.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有