bzoj2154 Crash的数字表格

来源:互联网 发布:涉税软件下载 编辑:程序博客网 时间:2024/06/05 23:49

题目链接:bzoj2154
题目大意:
给定n、m,求ni=1mj=1lcm(ij)
1≤n,m≤10000000

题解:
莫比乌斯反演
把原式化开

i=1nj=1mlcm(ij)=i=1nj=1mijgcd(i,j)

枚举约数(省略前面的了)
i=1nj=1md|i,d|jijd[gcd(i,j)=d]

交换枚举倍数和约数
d=1min(n,m)i=1ndj=1mdidjdd[gcd(i,j)=1]

[gcd(i,j)=1]ϵ((i,j)),套1μ=ϵ再约下分什么的就变成了
d=1min(n,m)di=1ndj=1mdijt|i,t|jμ(t)

再次交换枚举倍数和约数
d=1min(n,m)dt=1min(nd,md)i=1ndtj=1mdtitjtμ(t)

d=1min(n,m)dt=1min(nd,md)t2μ(t)i=1ndtj=1mdtij

sum(n,m)=ni=1mj=1ij=ni=1imj=1j这个直接上求和公式
则上式变成
d=1min(n,m)dt=1min(nd,md)t2μ(t)sum(ndt,mdt)

f(n,m)=min(n,m)t=1t2μ(t)sum(nt,mt)这个分块求。
于是上式又变成了
d=1min(n,m)d×f(nd,md)

这个也可以分块了。
所以时间复杂度大概是O(n)..吧
LL、mod什么的真的要注意啊不然WA到死。

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;#define N 10000100const LL ny=10050505;const LL mod=20101009;int cnt,pri[N/10];bool ispri[N];LL mu[N],pre[N];int mymin(int x,int y){return (x<y)?x:y;}void mobius(int lim){    cnt=0;mu[1]=1;    for (int i=2;i<=lim;i++)    {        if (!ispri[i]) {pri[++cnt]=i;mu[i]=-1;}        for (int j=1;j<=cnt && i*pri[j]<=lim;j++)        {            ispri[i*pri[j]]=true;            if (i%pri[j]==0)            {                mu[i*pri[j]]=0;                break;            }            mu[i*pri[j]]=-mu[i];        }    }}LL sum(int n,int m){    LL s1=(LL)(n)*(LL)(n+1)%mod*ny%mod;    LL s2=(LL)(m)*(LL)(m+1)%mod*ny%mod;    return s1*s2%mod;}LL f(int x,int y){    int r,lim=mymin(x,y);LL ans=0;    for (int i=1;i<=lim;i=r+1)    {        r=mymin(x/(x/i),y/(y/i));        ans=(ans+sum(x/i,y/i)*(pre[r]-pre[i-1])%mod)%mod;    }while (ans<0) ans+=mod;    return ans;}int main(){    //freopen("a.in","r",stdin);    //freopen("a.out","w",stdout);    int n,m,r,i,lim;LL ans=0;    scanf("%d%d",&n,&m);    lim=mymin(n,m);mobius(lim);    pre[1]=mu[1];for (i=2;i<=lim;i++) pre[i]=(pre[i-1]+(LL)i*i%mod*mu[i]%mod)%mod;    for (i=1;i<=lim;i=r+1)    {        r=mymin(n/(n/i),m/(m/i));        ans=(ans+(LL)(r-i+1)*(r+i)%mod*ny%mod*f(n/i,m/i)%mod)%mod;    }while (ans<0) ans+=mod;    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击