hdu 1695 GCD 【容斥原理】

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

题目大意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d)。

思路:让x,y都除上k,就是求gcd(x,y)=1的对数,gcd=1就是两个数互质,那么问题就可以转换成在(1,b/k)和(1,d/k)中互质的数的对数,题意告诉(1,3)和(3,1)为一种情况,所以限制x<=y即可;

要预处理求出所有数的素因数;

答案很大,用long long 记录答案;

#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+4;

vector<int>prime[N];
int vis[N];
void get_prime()//得到所有数的素因数
{
    memset(vis,0,sizeof(vis));
    for(int i=0;i<N-1;++i)
        prime[i].clear();
    for(int i=2;i<N-1;i+=2)
        prime[i].push_back(2);
    for(int i=3;i<N-1;i+=2)
    {
        if(!vis[i])
        {
            for(int j=i;j<N-1;j+=i)
            {
                vis[j]=1;
                prime[j].push_back(i);
            }
        }
    }
}

int solve(int n,int m)
{
    int sum=0;
    for(int i=1; i<(1<<prime[m].size()); ++i)
    {
        int k=0,pa=1;
        for(int j=0; j<prime[m].size(); ++j)
        {
            if(i&(1<<j))
            {
                k++;
                pa*=prime[m][j];
            }
        }
        int cur=n/pa;
        if(k&1) sum+=cur;
        else sum-=cur;
    }
    return sum;
}

int main()
{
    get_prime();
    int a,b,c,d,k;
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
        if(k==0)
        {
            printf("Case %d: 0\n",++cas);//注意格式
            continue;
        }
        b/=k;
        d/=k;
        if(b>d) swap(b,d);
        ll ans=0;
        for(int i=1; i<=d; i++)
        {
            int t=min(i,b);//如果此时i<b,就是求区间[1,i]中与i互质的数,
            ans+=t;        //否则就是求区间[1,b]中与i互质的数,因为是为了时x<=y;
              
            ans-=solve(t,i);//1~t之间与i互素的数的个数
        }
        printf("Case %d: %lld\n",++cas,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41984014/article/details/84856446