The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
InputThe first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.OutputFor each test case,output the answer on a single line.Sample Input
3 1 1 10 2 10000 72
Sample Output
1 6 260
题意:求有多少个1<=X<=N,满足gcd(X,N)>=M。
思路:即求Σd=gcd(X,N)>=M;枚举d,而d是M的因子,不超过根号N个;对枚举的d,用欧拉公式求得有多少个X满足gcd(X,N)=d;
#include<bits/stdc++.h> using namespace std; const int maxn=1000000; int p[maxn+10],vis[maxn+10],phi[maxn],cnt; void getprime() { phi[1]=1; for(int i=2;i<=maxn;i++){ if(!vis[i]) p[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&i*p[j]<=maxn;j++){ vis[i*p[j]]=1; phi[i*p[j]]=phi[i]*(p[j]-1); if(i%p[j]==0){ phi[i*p[j]]=phi[i]*p[j]; break; } } } } int tot,ans,fac[maxn]; void divide(int x) { for(int i=1;i*i<=x;i++){ if(x%i==0){ fac[++tot]=i; if(i*i!=x) fac[++tot]=x/i; } } } map<int,int>PHI; int getphi(int x) { if(x<=maxn) return phi[x]; if(PHI[x]) return PHI[x]; int res=x; for(int i=2;i*i<=x;i++) if(x%i==0) { res=res/i*(i-1); while(x%i==0) x/=i; } if(x>1) res=res/x*(x-1); PHI[x]=res; return res; } int main() { getprime(); int T,N,M,i,j; scanf("%d",&T); while(T--){ tot=ans=0; scanf("%d%d",&N,&M); divide(N); for(i=1;i<=tot;i++){ if(N/fac[i]>=M) ans+=getphi(fac[i]); } printf("%d ",ans); } return 0; }
---------------------------------分界线--------------------------------
再来看HDU5514。。。(虽然复杂度看似有些巧合)。
只要枚举M的因子,然后验证如果是属于某个gcd(a,M)的倍数,就可以累加其所到位子,求和的时候利用对称性,有公式Σ=φ(x)*m/2;。
(容斥定理也可以做,但是我想不出来)。。。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=100000; int p[maxn+10],vis[maxn+10],phi[maxn],cnt; void getprime() { phi[0]=1; phi[1]=1; for(int i=2;i<=maxn;i++){ if(!vis[i]) p[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&i*p[j]<=maxn;j++){ vis[i*p[j]]=1; phi[i*p[j]]=phi[i]*(p[j]-1); if(i%p[j]==0){ phi[i*p[j]]=phi[i]*p[j]; break; } } } } int tot,fac[maxn]; void divide(int x) { for(int i=1;i*i<=x;i++){ if(x%i==0){ fac[++tot]=i; if(i*i!=x) fac[++tot]=x/i; } } } int getphi(int x) { if(x<=maxn) return phi[x]; int res=x; for(int i=2;i*i<=x;i++) if(x%i==0) { res=res/i*(i-1); while(x%i==0) x/=i; } if(x>1) res=res/x*(x-1); return res; } int a[maxn],N,M; bool check(int x) { for(int i=1;i<=N;i++) if(x%a[i]==0) return true; return false; } int main() { getprime(); int T,Case=0,i; ll ans; scanf("%d",&T); while(T--){ tot=ans=0; scanf("%d%d",&N,&M); for(i=1;i<=N;i++){ scanf("%d",&a[i]); a[i]=__gcd(a[i],M); } divide(M); for(i=1;i<=tot;i++){ if(fac[i]!=M&&check(fac[i])) ans+=(ll)getphi(M/fac[i])*M/2; } printf("Case #%d: %lld ",++Case, ans); } return 0; }