1. 程式人生 > >求1~n中與m互質的數的個數(m>n) 附hdu1695題解(尤拉函式+容斥原理)

求1~n中與m互質的數的個數(m>n) 附hdu1695題解(尤拉函式+容斥原理)

int calc(int n,int m) { //求1~n 與m互質的數的個數
    int num=getFactors(m);  //先將m分解質因數
    int sum=0;  //先求出不互質的個數,最後用n減去該數
    for(int state=1; state<(1<<num); state++) {   //列舉狀態
        int tmp=1;
        int cnt=0;  
        for(int i=0; i<num; i++) {
            if(state&(1<<i)) {
                cnt++;
                tmp*=p[i];
            }
        }
        if(cnt&1)sum+=n/tmp;   //容斥
        else sum-=n/tmp;
    }
    return n-sum;
}

//////////////////////////////////////////////////////////////////////////以下是題解////////////////////////////////////////////////////////////////////////////////

http://acm.hdu.edu.cn/showproblem.php?pid=1695

GCD


Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4272    Accepted Submission(s): 1492
Problem Description
Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

Yoiu can assume that a = c = 1 in all test cases.
 
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
 
Output
For each test case, print the number of choices. Use the format in the example.
 
Sample Input
2 1 3 1 5 1 1 11014 1 14409 9
 
Sample Output
Case 1: 9 Case 2: 736427
Hint
For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).
 

宣告:此處搬運的kuangbin的題解,本人太懶。。

題意: 在1~a, 1~b中挑出(x,y)滿足gcd(x,y) = k , 求(x,y) 的對數 , a,b<=10^5


思路: gcd(x, y) == k 說明x,y都能被k整除, 但是能被k整除的未必gcd=k  , 必須還要滿足


互質關係. 問題就轉化為了求1~a/k 和 1~b/k間互質對數的問題


可以把a設定為小的那個數, 那麼以y>x來保持唯一性(題目要求, 比如[1,3] = [3,1] )


接下來份兩種情況:


1. y <= a , 那麼對數就是 1~a的尤拉函式的累計和(容易想到)


2. y >= a , 這個時候尤拉函式不能用了,怎麼做?  可以用容斥原理,具體見程式碼:

最後附上自己寫的程式碼:

#include<queue>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<set>
using namespace std;
typedef long long LL;
const int maxn=100000;
bool check[maxn+7];
int phi[maxn+7];
int prime[maxn+7];
int tot; //素數的個數
void phi_and_prime_table(int N) {
    memset(check,false,sizeof(check));
    phi[1]=1;
    tot=0;
    for(int i=2; i<=N; i++) {
        if(!check[i]) {
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0; j<tot; j++) {
            if(i*prime[j]>N)break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0) {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            } else {
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
}
int p[107],dex[107];
//設最大的素數為t,則x最多能取t*t
int getFactors(LL x) {  //將x的唯一分解存在p[]和dex[]中
    int fatcnt=0;
    LL tmp=x;
    for(int i=0; prime[i]<=tmp/prime[i]; i++) {
        dex[fatcnt]=0;
        if(tmp%prime[i]==0) {
            p[fatcnt]=prime[i];
            while(tmp%prime[i]==0) {
                dex[fatcnt]++;
                tmp/=prime[i];
            }
            fatcnt++;
        }
    }
    if(tmp!=1) {
        p[fatcnt]=tmp;
        dex[fatcnt++]=1;
    }
    return fatcnt;
}
int calc(int n,int m) { //求1~n 與m互質的數的個數
    int num=getFactors(m);  //先將m分解質因數
    int sum=0;  //先求出不互質的個數,最後用n減去該數
    for(int state=1; state<(1<<num); state++) {   //列舉狀態
        int tmp=1;
        int cnt=0;
        for(int i=0; i<num; i++) {
            if(state&(1<<i)) {
                cnt++;
                tmp*=p[i];
            }
        }
        if(cnt&1)sum+=n/tmp;   //容斥
        else sum-=n/tmp;
    }
    return n-sum;
}
int q,a,w,b,k,aa,bb;
int main() {
    // freopen("in.txt","r",stdin);
    phi_and_prime_table(maxn);
    int t;
    cin>>t;
    int now=0;
    while(t--) {
        scanf("%d%d%d%d%d",&q,&aa,&w,&bb,&k);
        if(k == 0 || k > aa || k > bb) {
            printf("Case %d: 0\n",++now);
            continue;
        }
        if(bb>aa)swap(aa,bb);
        a=aa/k,b=bb/k;
        LL ans=0;
        for(int i=1; i<=b; i++) {
            ans+=phi[i];
        }
        for(int i=b+1; i<=a; i++) {
            ans+=calc(b,i);
        }
        printf("Case %d: %I64d\n",++now,ans);
    }
    return 0;
}