卷积:
两个多项式的卷积:
之后引入
狄利克雷卷积是两个数的因子的成绩为n,且两个因子都要是整数。
突破卷积的目标系数为两个下标的和为p
可以简单的记忆为 和 与 积
而狄利克雷卷积有如此复杂的格式,自然有良好的性质。
以下列举本题所需的:
莫比乌斯函数与1的卷积为单位函数
形式化:
(其实以上狄利克雷卷积性质,即位莫比乌斯反演的最常见形式;)
单位函数是:
只有当自变量取1的时候,函数值为1
其余为0
即题目中的自变量为gcd(a_1,a_2,…,a_n)
根据以上内容可以把题目的目标写为:(g为和不超过m函数)
求此函数的值
根据莫比乌斯反演,将gcd(a_1,a_2,…,a_n)作为单位函数的自变量:
d是gcd的因子,而gcd是所有的共同因子,那么可以表述为d是每个a_i的因子
注意,以下将会发生一个神奇的变化:
(这里的a_i与上一个公式的a_i不同,详细看如下内容)
本人认为以上变换才是莫比乌斯反演题目的最难部分,相当于一个整除分块,把d提取出来,然后对于a_i 来说在无d的限制条件的情况下其取值范围为l_i,r_i
而加上限制条件之后变成了,l_i,r_i内的d的倍数的数
简述为最小值为[(l_i + d - 1) / d]*d 即向上取整
最大为[r_i / d]*d 这里的 ‘/’ 是C++运算符。
至此,题目即可枚举d然后进行DP,由于调和级数所以每次dp为nlogm
加上枚举d总复杂为mnlogm
这里的dp有些技巧
先假设dp[i][j]为选前i个a,和为j,如果当前取值k
那么dp[i][j] = dp[i-1][j - k]
需要枚举k与j,复杂度nm*m
发现对于每个j,是被一个区间更新,有如下优化:
但是如果考虑第二维度为前缀和:
那么
dp[i][j] = dp[i-1][j-l] - dp[i - 1][j - r - 1];
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int Mn = 1e5 + 5;
#define ll long long
const ll Mod = 998244353;
ll dp[55][Mn];
ll mib[Mn],prime[Mn];
int cnt = 0,is[Mn];
void inint(){
mib[1] = 1;
for(ll i = 2;i <= Mn - 5;i ++){
if(is[i] == 0) prime[++cnt] = i,mib[i] = -1;
for(int j = 1;j <= cnt && prime[j] * i <= Mn - 5;j ++){
is[prime[j] * i] = 1;
if(i % prime[j] == 0){
mib[i * prime[j]] = 0;
break;
}
mib[i * prime[j]] = - mib[i];
}
}
}
ll l[55],r[55];
int main(){
inint();
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++) scanf("%d%d",l + i,r + i);
ll ans = 0;
for(int d = 1;d <= m;d ++){
int mx = m / d;
for(int i = 0;i <= mx;i ++) dp[0][i] = 1;
for(int i = 1;i <= n;i ++){
int L = (l[i] + d - 1) / d,R = r[i] / d;
if(L > R){
dp[n][mx] = 0;
break;
}
for(int j = 1;j <= mx;j ++){
dp[i][j] = dp[i][j - 1];//把1到j-1都继承过来
//下面是只算和为j的情况,加上上面的1到j-1,就j以内的所有的
if(j - L >= 0)
dp[i][j] += dp[i - 1][j - L];
dp[i][j] %= Mod;
if(j - R - 1 >= 0)
dp[i][j] -= dp[i - 1][j - R - 1];
dp[i][j] += Mod;
dp[i][j] %= Mod;
}
}
ans += (mib[d] * dp[n][mx]);
ans += Mod;
ans %= Mod;
}
printf("%lld\n",ans);
return 0;
}