题意:在[1,c]和[1,d]中分别选两个数x,y,求gcd(x,y)==k的数的对数,其中(x,y)与(y,x)为同一种方案。
思路:假设c<d,在区间[1,c]可以直接用欧拉函数求解。然后枚举[c+1,d]的每个数,求在[1,c]中与这个数互质的数的个数,这个可以通过容斥原理解决。。。交完以后发现有好多0ms过掉的……上网翻了翻题解,貌似可以用莫比乌斯反演做?唉,慢慢学吧~
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=100000+10; ll phi[maxn]; void euler_table() { phi[0]=0;phi[1]=1; for(int i=2;i<maxn;++i) phi[i]=i; for(int i=2;i<maxn;++i) { if(phi[i]==i) { for(int j=i;j<maxn;j+=i) phi[j]=phi[j]-phi[j]/i; } } for(int i=2;i<maxn;++i) phi[i]+=phi[i-1]; } int factor[20],tot,N; ll ans; void dfs(int pos,ll now,int sign) { ans+=N/now*sign; for(int i=pos+1;i<tot;++i) dfs(i,now*factor[i],-sign); } ll cal(int m,int n) { N=n;tot=0;ans=0; int M=sqrt(m+0.5); for(int i=2;i<=M;++i) { if(m%i==0) { factor[tot++]=i; while(m%i==0) m/=i; } } if(m>1) factor[tot++]=m; for(int i=0;i<tot;++i) dfs(i,factor[i],1); return n-ans; } ll solve(int c,int d,int k) { if(k==0) return 0; c/=k;d/=k; if(c>d) swap(c,d); ll res=phi[c]; for(int i=c+1;i<=d;++i) res+=cal(i,c); return res; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,tcase=0,a,b,c,d,k; euler_table(); scanf("%d",&t); while(t--) { tcase++; scanf("%d%d%d%d%d",&a,&c,&b,&d,&k); printf("Case %d: %I64d\n",tcase,solve(c,d,k)); } return 0; }