[BZOJ 2301]Problem B 莫比烏斯反演
阿新 • • 發佈:2017-12-07
講解 莫比烏斯 ima 比較 images include define 技術 2-2
紀念莫比烏斯反演首題!同時感謝Antileaf學長的耐心講解!
我們可以用容斥原理搞
令f(d)為1<=x<=n,1<=y<=m且gcd(x,y)=d的數對(x,y)的個數
則可設:
可得F(i)為1<=x<=n,1<=y<=m且i|gcd(x,y)的數對(x,y)的個數
化簡可得
莫比烏斯反演一下
枚舉i的每一個倍數d,我們就可以O(n)詢問了
但是這樣明顯不行,所以我們還需要優化:
設,可以得到
我們設,,則可以得到
我們註意到,枚舉k的時候,對於一些k,後邊向下取整的值是相等的
那麽在相等的區間內的答案,就是這一段區間的μ值之和*後邊的不變的部分
μ值之和可以用前綴和搞出來,可是怎麽找這一段呢
借鑒PoPoQQQ的打法:
if(n>m) swap(n,m); for(i=1;i<=n;i=last+1) { last=min(n/(n/i),m/(m/i)); res+=(n/i)*(m/i)*(sum[last]-sum[i-1]);//sum是μ的前綴和 } return res;
可以感性理解為對於兩個n,m,向下取整相等的分別可以劃分成一段一段的。
因為我們要的一段區間是n與m對於k向下取整都不變 ,所以我們去它們的一段段的公共區間就可以了
這是一道比較典型的例題,貼上代碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 50100 int mu[N],prime[N],notprime[N],sum[N]; void getmu(){ mu[1]=1; pos(i,2,N-10){ if(!notprime[i]){ prime[++prime[0]]=i; mu[i]=-1; } for(int j=1;j<=prime[0]&&prime[j]*i<=N-10;j++){ notprime[prime[j]*i]=1; if(i%prime[j]==0){ mu[prime[j]*i]=0;break; } mu[prime[j]*i]=-mu[i]; } } sum[0]=mu[0]; pos(i,1,N-10) sum[i]=sum[i-1]+mu[i]; } int a,b,c,d,k,n,m; int getans(int x,int y){ if(x>y) swap(x,y); n=x/k;m=y/k; int last(0),ans(0); for(int i=1;i<=n;i=last+1){ last=min(n/(n/i),m/(m/i)); ans+=(n/i)*(m/i)*(sum[last]-sum[i-1]); } return ans; } int t; int main(){ scanf("%d",&t); getmu(); pos(i,1,t){ scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%d\n",getans(b,d)-getans(a-1,d)-getans(b,c-1)+getans(a-1,c-1)); } return 0; }
[BZOJ 2301]Problem B 莫比烏斯反演