hdu1695 GCD 【欧拉函数+容斥】

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

题意:[1,a],[1,b] 有多少对GCD(x,y)=k。

分析:约掉k后GCD(x,y)=1,枚举一段区间问题变成,i在[1,b/k]中有多少个与他互质的数。可以用容斥求出,过程:

区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的成绩的倍数个数)-(区间中i的每4个质因数的乘积)+...

然后减去不互质的剩下的就是互质的数。

由于题目中[2,3],[3,2]属于同一对。直接容斥还是会有重复的,我们知道欧拉函数可以求出比i小的且与他互质的数,这样我们就可以求出[1,b],[1,b]

之间的数,然后容斥[1,b][b+1,d]的数就行了。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100005
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef __int64 ll;
int read() {
    char c;
    int ans=0,f=1;c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {ans=ans*10+c-'0';c=getchar();}
    return  ans*f;
}
ll eular[Mn];
int s[Mn][20],tot;
void Eular() {
    eular[1]=1;
    for(int i=2;i<=Mn;i++) {
        if(!eular[i])
        for(int j=i;j<=Mn;j+=i) {
            if(!eular[j]) eular[j]=j;
            eular[j]=eular[j]*(i-1)/i;
            s[j][++s[j][0]]=i;
        }
        eular[i]+=eular[i-1];
    }
}
ll dfs(int pos,int v,int x) {
    ll re=0;
    for(int i=pos;i<=s[x][0];i++) {
        re+=v/s[x][i]-dfs(i+1,v/s[x][i],x);
    }
    return re;
}
int main() {
    Eular();
    int t=read();
    for(int cas=1;cas<=t;cas++) {
        int a=read(),b=read(),c=read(),d=read(),k=read();
        if(!k) {
            printf("Case %d: 0\n",cas);
            continue;
        }
        if(b>d) swap(b,d);
        b/=k;d/=k;
        ll sum=eular[b];
        for(int i=b+1;i<=d;i++) {
            sum+=b-dfs(1,b,i);
        }
        printf("Case %d: %I64d\n",cas,sum);
    }
    return 0;
}


你可能感兴趣的:(hdu1695 GCD 【欧拉函数+容斥】)