hdu1695 GCD
好题
整理下思路~~
前面做过一道这样的问题:
1……N里有多少个数X,满足(X,N)=C
一种解法是这样的:
X=x*C,N=n*C,则(x,n)=1
即求x的个数
(x,n)=1 && x<=n( x*C<=n*C=N )
则x的个数即为phi(n)=phi(N/c)
现在这个问题是这样的:
X属于1……a,Y属于1……b (不妨设a<=b)
求解数对X,Y的个数,满足(X,Y)=C
我的解法是这样的:
X=x*C,Y=y*C,(x,y)=1
枚举x,对于一个特定的x,y满足:
(x,y)=1;
x<=y;
y<=b/C ( y*C=Y<=b )
对x分解素因子,然后在区间[x,b/C]里利用容斥原理求解
写着写着发现,如果枚举y,那么x满足
(x,y)=1
x<=y
x*C=X<=a,x<=a/C
则
对于y<=a/C,x满足 (x,y)=1 && x<=y 即为phi(y)
对于y>a/C, x满足 (x,y)=1 && x<=a/C,还是利用容斥原理求解
本来想试着只用欧拉函数解决,没成功,这样的话应该没快多少。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 const int maxp = 15,maxn = 100000; 8 9 int p[maxp],pk; 10 int prime[maxn+5],pd[maxn+5],pnum; 11 12 void gp() 13 { 14 for(int i=2;i<=maxn;i++) 15 { 16 if( !pd[i] ) prime[++pnum]=pd[i]=i; 17 for(int j=1;j<=pnum && prime[j]<=maxn/i;j++) 18 { 19 pd[i*prime[j]]=prime[j]; 20 if( i%prime[j]==0 ) break; 21 } 22 } 23 } 24 25 void fenjie(int n) 26 { 27 pk=0; 28 while( n>1 ) 29 { 30 int d=pd[n]; 31 p[++pk]=d; 32 while( n%d==0 ) n/=d; 33 } 34 } 35 36 void rc(int idx,int cur,int c,int n,bool flag,LL& ans) 37 { 38 int tmp; 39 for(int i=idx;i<=pk;i++) 40 { 41 tmp=cur*p[i]; 42 if( flag ) ans+=n/tmp-c/tmp; 43 else ans-=n/tmp-c/tmp; 44 rc(i+1,tmp,c,n,!flag,ans); 45 } 46 } 47 48 int main() 49 { 50 gp(); 51 int T,a,b,c,d,k; 52 53 scanf("%d",&T); 54 for(int cs=1;cs<=T;cs++) 55 { 56 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 57 a=b;b=d; 58 printf("Case %d: ",cs); 59 if( !k || k>a || k>b ) {puts("0");continue;} 60 if( a>b ) swap(a,b); 61 LL ans=b/k,tmp; 62 for(int i=2;i*k<=a;i++) 63 { 64 fenjie(i); 65 tmp=0; 66 rc(1,1,i-1,b/k,true,tmp); 67 ans+=b/k-i+1-tmp; 68 } 69 printf("%I64d\n",ans); 70 } 71 return 0; 72 }