莫比乌斯反演
题目大意:从(1,b)中选一个数x,(1,d)中选一个数y。求gcd(x,y)=k的个数(3,4),(4,3)只算一遍。
gcd(x,y) == k等价于gcd(x/k,y/k)==1
那么题目就变为在[1,b/k],[,d/k]中选择x,y满足gcd(x,y) == 1 的个数了 ,然后去重即可.
我们可以假设
F(k):表示gcd(x,y) == (k的倍数的个数).
f(k):表示gcd(x,y)==k的个数。
而我们最后要求得则是f(1) .
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<map> #include<queue> #include<iomanip> #include<vector> #include<functional> using namespace std; typedef long long ll; const int maxn = 100005; bool check[maxn]; int prime[maxn]; int mu[maxn]; void Moblus(){ //莫比乌斯的各项系数打表 memset(check,false,sizeof(check)); mu[1] = 1; int tot = 0; for(int i = 2;i<maxn;i++) { if(!check[i]) { prime[tot++] = i; mu[i] = -1; } for(int j =0;j<tot;j++) { if(i*prime[j]>maxn) break; check[i*prime[j]] = true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else mu[i*prime[j]] = -mu[i]; } } } int main(){ int T; scanf("%d",&T); Moblus(); for(int kase = 1;kase<=T;kase++) { int a,b,c,d,k; cin>>a>>b>>c>>d>>k; if(k==0) { cout<<"Case "<<kase<<": 0"<<endl; continue; } b /=k; d /=k; if(b>d) swap(b,d); ll ans1 = 0; for(int i =1;i<=b;i++) ans1 += (ll)mu[i] * (b/i) * (d/i); //F(1) = f(1)+f(2)+....+f(d) ll ans2 = 0; for(int i =1;i<=b;i++) //重复部分(3,4)与(4,3) x,y都属于1~b 的那部分 ans2 += (ll)mu[i] * (b/i) * (b/i); printf("Case %d: %lld\n",kase,ans1-ans2/2); } return 0; }

浙公网安备 33010602011771号