求有多少长 n n n 的序列 a a a 满足:
- l i ≤ a i ≤ r i l_i\le a_i\le r_i li≤ai≤ri
- ∑ i = 1 n a i ≤ m \sum_{i=1}^{n}a_i\le m ∑i=1nai≤m
- gcd ( a 1 , … , a n ) = 1 \gcd(a_1,\dots,a_n)=1 gcd(a1,…,an)=1
答案对 998244353 998244353 998244353 取模。
样例输入 #1
2 4
1 3
1 2
样例输出 #1
4
只看前两个条件,我们发现就直接是一个背包问题,枚举 a i a_i ai,枚举背包状态,然后遍历所有的位置,时间复杂度是 O ( m 2 n ) O(m^2n) O(m2n),很显然,这个时间复杂度不能满足我们的要求,需要注意的是,题目问的是 < = m <=m <=m。
dp[0]=1;//意义是:恰好等于下标的种类数
for(int i=1;i<=n;i++){
memset(f,0,sizeof f);
for(int j=l[i];j<=r[i];j++){
for(int k=j;k<=m;j++){
f[k]+=dp[k-j];
}
}
dp[0]=0;
for(int j=1;j<=m;j++)dp[i]=dp[i]+f[i];
}
但是其实我们发现,中间的状态转移,用前缀和就可以完美解决
for(int i=0;i<=m;i++)dp[i]=1;//意义是:小于等于下标的种类数(因此使用前缀和)
for(int i=1;i<=n;i++){
memset(f,0,sizeof f);
for(int j=l[i];j<=m;j++){
f[j]+=dp[j-l[i]];
if(j>r[i]){
f[j]-=dp[j-r[i]-1];//要[l[i],r[i]]区间的数,大于r[i]的数无法转移,因此减掉
}
}
dp[0]=0;
for(int j=1;j<=m;j++)dp[i]=dp[i-1]+f[i];
}
时间复杂度是 O ( n m ) O(nm) O(nm)还可以~
于是现在求的问题就是
∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ [ g c d ( a 1 , a 2 . . . a n ) = 1 ] \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*[gcd(a_1,a_2...a_n)=1] a1=l[1]∑r[1]a2=l[2]∑r[2]...an=l[n]∑r[n]f(a1,a2...an)∗[gcd(a1,a2...an)=1]
转换一下
∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ ε ( g c d ( a 1 , a 2 . . . a n ) = 1 ) \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*ε(gcd(a_1,a_2...a_n)=1) a1=l[1]∑r[1]a2=l[2]∑r[2]...an=l[n]∑r[n]f(a1,a2...an)∗ε(gcd(a1,a2...an)=1)
展开
∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ ∑ d ∣ g c d ( a 1 , a 2 . . . a n ) μ ( d ) \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*\displaystyle\sum_{d|gcd(a_1,a_2...a_n)}^{}μ(d) a1=l[1]∑r[1]a2=l[2]∑r[2]...an=l[n]∑r[n]f(a1,a2...an)∗d∣gcd(a1,a2...an)∑μ(d)
交换枚举顺序
∑ d = 1 m μ ( d ) ∑ a 1 = l [ 1 ] / d r [ 1 ] / d ∑ a 2 = l [ 2 ] / d r [ 2 ] / d . . . ∑ a n = l [ n ] / d r [ n ] / d f ( a 1 ∗ d , a 2 ∗ d . . . a n ∗ d ) \displaystyle\sum_{d=1}^{m}μ(d)\displaystyle\sum_{a_1=l[1]/d}^{r[1]/d}\displaystyle\sum_{a_2=l[2]/d}^{r[2]/d}...\displaystyle\sum_{a_n=l[n]/d}^{r[n]/d}f(a_1*d,a_2*d...a_n*d) d=1∑mμ(d)a1=l[1]/d∑r[1]/da2=l[2]/d∑r[2]/d...an=l[n]/d∑r[n]/df(a1∗d,a2∗d...an∗d)
枚举倍数是调和级数,时间复杂度是 O ( l n m ) O(ln m) O(lnm),枚举 n n n个数,那么时间复杂度是 n l n m nlnm nlnm,前面的 d d d枚举起来是 m m m,因此时间复杂度是 O ( n m l n m ) O(nmln m) O(nmlnm)
#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
const int mod = 998244353;
int check[N + 5], n, m;
int mu[N + 5], p[N + 5];
bool flg[N + 5];
int dp[N];
int l[N];
int r[N];
void mobius()
{
int tot = 0;
mu[1] = 1;
for (int i = 2; i <= N; ++i)
{
if (!flg[i])
{
p[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * p[j] <= N; ++j)
{
flg[i * p[j]] = 1;
if (i % p[j] == 0)
{
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = -mu[i];
}
}
}
signed main()
{
mobius();
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> l[i] >> r[i];
int ans = 0;
for (int d = 1; d <= m; d++)
{
if (!mu[d])
continue;
int tot = 0;
int sum = m / d;
vector<int> dp(sum + 1, 1);
for (int i = 1; i <= n; i++)
{
vector<int> f(sum + 1);
for (int j = (l[i] + d - 1) / d; j <= sum; j++)
{
f[j] = dp[j - (l[i] + d - 1) / d];
if (j >= r[i] / d + 1)
f[j] = (f[j] - dp[j - r[i] / d - 1] + mod) % mod;
}
dp[0] = 0;
for (int j = 1; j <= sum; j++)
dp[j] = (dp[j - 1] + f[j]) % mod;
}
ans = ((ans + dp[sum] * mu[d]) % mod + mod) % mod;
}
cout << ans << endl;
}