题意:给定a,b,c,d,k
x属于[1 , c],y属于[1 , d],求满足gcd(x,y)=k的对数。其中<x,y>和<y,x>算相同。
思路:不妨设c<d,x<=y。问题可以转化为x属于[1,c / k ],y属于[1,d/k ],x和y互质的对数。
那么假如y<=c/k,那么对数就是y从1到c/k欧拉函数的和。如果y>c/k,就只能从[ c/k+1 , d ]枚举,然后利用容斥。详见代码:
/********************************************************* file name: hdu1695.cpp author : kereo create time: 2015年02月11日 星期三 18时08分43秒 *********************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int N=100+50; const int MAXN=100000+50; const int inf=0x3fffffff; const double eps=1e-8; const int mod=1000000000+7; #define L(x) (x<<1) #define R(x) (x<<1|1) #define PII pair<int, int> #define mk(x,y) make_pair((x),(y)) int primecnt,factcnt; int prime[MAXN],euler[MAXN],factor[N][2]; void getprime(){ primecnt=0; memset(prime,0,sizeof(prime)); for(int i=2;i<MAXN;i++){ if(!prime[i]) prime[primecnt++]=i; for(int j=0;j<primecnt && prime[j]<=MAXN/i;j++){ prime[prime[j]*i]=1; if(i%prime[j] == 0) break; } } } void geteuler(){ memset(euler,0,sizeof(euler)); euler[1]=1; for(int i=2;i<MAXN;i++){ if(!euler[i]){ for(int j=i;j<MAXN;j+=i){ if(!euler[j]) euler[j]=j; euler[j]=euler[j]/i*(i-1); } } } } int getfactor(int x){ factcnt=0; for(int i=0;prime[i]<=x/prime[i];i++){ factor[factcnt][1]=0; if(x%prime[i] == 0){ factor[factcnt][0]=prime[i]; while(x%prime[i] == 0){ x/=prime[i]; factor[factcnt][1]++; } factcnt++; } } if(x!=1){ factor[factcnt][0]=x; factor[factcnt++][1]++; } return factcnt; } int solve(int n,int m){ int ans=0; getfactor(m); for(int i=1;i<(1<<factcnt);i++){ int cnt=0,res=1; for(int j=0;j<factcnt;j++){ if(i&(1<<j)){ cnt++; res*=factor[j][0]; } } if(cnt & 1) ans+=n/res; else ans-=n/res; } return n-ans; } int main(){ int T,kase=0; scanf("%d",&T); getprime(); geteuler(); while(T--){ printf("Case %d: ",++kase); int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); if(k == 0 || k>b || k>d){ printf("0\n"); continue; } if(b>d) swap(b,d); b/=k; d/=k; ll ans=0; for(int i=1;i<=b;i++) ans+=euler[i]; for(int i=b+1;i<=d;i++) ans+=solve(b,i); printf("%I64d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/u011645923/article/details/43737013