【刷题记录】BZOJ2154 crash的数字表格 莫比乌斯反演
治好了我多年的公式恐惧症
https://www.luogu.org/problemnew/show/P1829
(放洛谷题号的原因是BZOJ上很多内容是限制级的(雾))
题目大意:已知M,N,求
(我采用数论教材上的方法表示最大公因数,即(i,j)表示i,j的最大公约数)
那么,我们开始吧。
不妨设n<m
令,有
即
接下来是莫比乌斯函数的性质:当且仅当d = 1
转化为枚举x
枚举t=dx
中间两个和式为等差数列求和,可以O(1)得到结果
经过完全归纳法证明,为积性函数
证明如下:
当i为质数时,显然
记p为任意质数
当时
有
证完
接下来考虑线性筛的实现
考虑当
有
所以线性筛完成
依靠线性筛预处理后,可以O(n)时间预处理,再用O(n)时间得出结果
然而此题还可以再次优化
考虑到和可以数论分块
时间复杂度可以优化至O(n+sqrt(n))
这样可以解决多组数据的情况
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m;
#define ll long long
#define mod 20101009
#define inv2 10050505
#define N 10000000
int prime[N+9],mu[N+9];
bool notprime[N+8];
ll sum(int x)
{
return (((((ll)x*(x+1))%mod)*inv2)%mod);
}
int main()
{
scanf("%d%d",&n,&m);
if(n>m)swap(n,m);
notprime[1]=mu[1]=1;int tot = 0;
for(int i = 2; i <= n; i ++)
{
if(!notprime[i])
{
prime[++tot]=i;
mu[i]=(1-i+mod)%mod;
}
for(int j = 1; j <= tot &&prime[j]*i<=n; j ++)
{
notprime[prime[j]*i]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=mu[i];
break;
}
else
{
mu[i*prime[j]]=(((ll)mu[i]*(1-prime[j])%mod)+mod)%mod;
}
}
mu[i]=((((ll)i*mu[i])%mod+mu[i-1])%mod+mod)%mod;
}
int ans = 0;
for(int i = 1,last; i <= n; i =last +1)
{
last = min(n/(n/i),m/(m/i));
ans = (((((sum(n/i)*sum(m/i))%mod)*(mu[last]-mu[i-1]))%mod+mod)%mod+ans)%mod;
}
printf("%d",ans);
}