bzoj 2301(Mobius)

来源:互联网 发布:2016淘宝网红店铺排名 编辑:程序博客网 时间:2024/06/16 21:04

推出式子然后分块求和(还需使用一下容斥原理)。
分析:令f(n,m,i)表示在1<=x<=n,1<=y<=m,满足gcd(x,y)是i的(x,y)的对数。
ans=f(c,d,i)−f(a−1,d,i)−f(b,c−1,i)+f(a−1,c−1,i)其中1<=x<=n,1<=y<=m,满足gcd(x,y)是i的(x,y)的对数也等价于1<=x<=n/i,1<=y<=m/i时(x,y)互质(gcd(x,y)=1)的对数,即
f(n,m,i)=f(n/i,m/i,1)

令F(i)表示满足i|gcd(x,y)的(x,y)的对数。
可以得到一个显然的事实F(i)=⌊ni⌋⌊mi⌋。
根据莫比乌斯反演定理 (不会的可以去看看ACdreamer博客)
F(i)=∑i|df(d)=>f(i)=∑i|dμ(di)F(d)=∑i|dμ(di)⌊nd⌋⌊md⌋
后面O(√n)进行分块求和即可,此处不再赘述

/*     ans=calc(b,d,k)-calc(a-1,d,k)-calc(c-1,b,k)+calc(a-1,c-1,k); */ #include<bits/stdc++.h>using namespace std;typedef long long ll;const int MAXN=5e5+2;int mu[MAXN],prime[MAXN],tot=0,a,b,c,d,k;bool vis[MAXN];inline void linear_shaker() {    mu[1]=1;    memset(vis,false,sizeof(vis));    for (register int i=2;i<MAXN;++i) {        if (!vis[i]) prime[++tot]=i,mu[i]=-1;        for (int j=1;j<=tot&&i*prime[j]<MAXN;++j) {            vis[i*prime[j]]=true;            if (i%prime[j]==0) {mu[i*prime[j]]=0;break;}            mu[i*prime[j]]=-mu[i];        }    }    for (register int i=2;i<MAXN;++i) mu[i]+=mu[i-1];}inline int read() {    int x=0;char c=getchar();    while (c<'0'||c>'9') c=getchar();    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();    return x;}inline ll cal(int n,int m) {    int t=n>m?m:n,last;ll ret=0;    for (int i=1;i<=t;i=last+1) {        last=min(n/(n/i),m/(m/i));        ret+=1ll*(mu[last]-mu[i-1])*(ll)(n/i)*(m/i);    }    return ret;}int main() {    linear_shaker();    int kase=read();    while (kase--) {        a=read(),b=read(),c=read(),d=read(),k=read();        a=(a-1)/k,b/=k,c=(c-1)/k,d/=k;        printf("%lld\n",cal(a,c)+cal(b,d)-cal(a,d)-cal(c,b));    }    return 0;}
原创粉丝点击