標籤:數學 組合數學
連結:http://acm.hdu.edu.cn/showproblem.php?pid=1695
題意:在[a,b]中的x,在[c,d]中的y,求x與y的最大公約數為k的組合有多少。(a=1, a <= b <= 100000, c=1, c <= d <= 100000, 0 <= k <= 100000)
思路:因為x與y的最大公約數為k,所以xx=x/k與yy=y/k一定互質。要從a/k和b/k之中選擇互質的數,枚舉1~b/k,當選擇的yy小於等於a/k時,可以選擇的xx數為Euler(yy),當yy大於a/k時,就要用容斥原理來找到yy的質因數,在a/k範圍內找到與yy互質的數。
代碼:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <map>#include <cstdlib>#include <queue>#include <stack>#include <vector>#include <ctype.h>#include <algorithm>#include <string>#include <set>#include <ctime>#define PI acos(-1.0)#define maxn 1<<20#define INF 0x7fffffff#define eps 1e-8typedef long long LL;typedef unsigned long long ULL;using namespace std;LL ans=0;LL S=0;LL sum2;LL euler[100050];void init(){ memset(euler,0,sizeof(euler)); euler[1] = 1; for(int i = 2; i <= 100000; i++) if(!euler[i]) for(int j = i; j <= 100000; j += i) { if(!euler[j]) euler[j] = j; euler[j] = euler[j]/i*(i-1); }}void factor(int n,int a[maxn],int b[maxn],LL &tt){ int temp,i,now; temp=(int)((double)sqrt(n)+1); tt=0; now=n; for(i=2; i<=temp; i++) { if(now%i==0) { a[++tt]=i; b[tt]=0; while(now%i==0) { ++b[tt]; now/=i; } } } if(now!=1) { a[++tt]=now; b[tt]=1; }}int dfs(int aa[],int pos,int res,int sum,int b,int tot)//res乘積,sum乘數的個數{ if(pos+1<=tot) dfs(aa,pos+1,res,sum,b,tot); sum++; res*=aa[pos]; if(sum%2) sum2+=b/res; else sum2-=b/res; if(pos+1<=tot) dfs(aa,pos+1,res,sum,b,tot); return 0;}int main(){ int T,tt=0,aa[40],bb[40]; init(); while(~scanf("%d",&T)) { tt=0; while(T--) { tt++; int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("Case %d: ",tt); if(k==0) { printf("0\n"); continue; } if(d<b) swap(b,d); b/=k; d/=k; if(!b) { printf("0\n"); continue; } ans=0; for(int i=1; i<=b; i++) ans+=euler[i]; for(int i=b+1; i<=d; i++) { sum2=0; factor(i,aa,bb,S); dfs(aa,1,1,0,b,S); ans+=b-sum2; } printf("%I64d\n",ans); } } return 0;}