hdu1695 两个区间各取一个数gcd==k对数:莫比乌斯反演
首先(1,b)(1,d)->(1,b/k)(1,d/k)转化为互质对数
设F(k)为gcd(x,y)为k的倍数的对数->F(k)=(b/k)*(d/k)
f[1]=mu[1]*F[1]+mu[2]*F[2]+...mu[m]*F[m]
再减去重复计算的,变了F[i]再做一遍==
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 100005 6 #define LL long long 7 LL vis[maxn],prime[maxn],mu[maxn]; 8 void mobius() 9 { 10 LL cnt=0,i,j; 11 memset(vis,0,sizeof(vis)); 12 mu[1]=1; 13 for (i=2;i<=maxn;i++){ 14 if (vis[i]==0){ 15 prime[++cnt]=i; 16 mu[i]=-1; 17 } 18 for (j=1;j<=cnt;j++){ 19 if (i*prime[j]>maxn) break; 20 vis[i*prime[j]]=1; 21 if (i%prime[j]==0){mu[i*prime[j]]=0; break;} 22 else mu[i*prime[j]]=-mu[i]; 23 } 24 } 25 } 26 int main() 27 { 28 LL T,t,a,b,c,d,k,a1,a2,i; 29 mobius(); 30 scanf("%I64d",&T); 31 for (t=1;t<=T;t++){ 32 scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&k); 33 printf("Case %I64d: ",t); 34 if (k==0) {printf("0\n"); continue; } 35 b/=k; d/=k; 36 if (b>d) swap(b,d); 37 a1=a2=0; 38 for (i=1;i<=b;i++){ 39 a1+=mu[i]*(b/i)*(d/i); 40 a2+=mu[i]*(b/i)*(b/i); 41 } 42 printf("%I64d\n",a1-a2/2); 43 } 44 return 0; 45 }
关于莫比乌斯反演专题学习和理解过两天再补,好困要碎TUT
很久以前写的一个容斥版本,也放上来吧,(对比发现跑的好慢
1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 int temp,d,a,sum,num[100005],prime[100005],vis[100005]; 5 long long gcd(long long x,long long y) 6 { 7 if (y==0) return x; 8 return gcd(y,x%y); 9 } 10 void dfs(int now,int flag,long long bei) 11 { 12 if (bei>d) return; 13 if (flag) temp+=d/bei-a/bei; 14 else temp-=d/bei-a/bei; 15 for (int i=now+1;i<=sum;i++) 16 dfs(i,1-flag,num[i]/gcd(bei,num[i])*bei); 17 } 18 int main() 19 { 20 int cnt,i,j,T,t,k,b,c,sqr; 21 long long ans; 22 cnt=0; 23 memset(vis,0,sizeof(vis)); 24 for (i=2;i<=100000;i++) 25 if (!vis[i]) 26 { 27 cnt++; 28 prime[cnt]=i; 29 for (j=2;i*j<=100000;j++) vis[i*j]=1; 30 } 31 scanf("%d",&T); 32 for (t=1;t<=T;t++) 33 { 34 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 35 if (k==0) { printf("Case %d: 0\n",t); continue;} 36 b/=k; d/=k; 37 if (b>d) {a=b; b=d; d=a; } 38 if (b!=0) ans=d; else ans=0; 39 for (i=2;i<=b;i++) 40 { 41 a=i; sum=0; 42 sqr=(int)sqrt(1.0*a); 43 for (j=1;j<=cnt&&prime[j]<=sqr;j++) 44 if (a%prime[j]==0) 45 { 46 sum++; 47 num[sum]=prime[j]; 48 while (a%prime[j]==0) a/=prime[j]; 49 } 50 if (a!=1) {sum++; num[sum]=a; } 51 temp=0; a=i; 52 for (j=1;j<=sum;j++) dfs(j,1,num[j]); 53 ans=ans+(long long)(d-a-temp); 54 } 55 printf("Case %d: %I64d\n",t,ans); 56 } 57 }