hdu4135Co-prime-容斥原理

题意:给定a、b、c,求a到b区间内与c互质的数。


分析:我们可以先转化下:用(1,b)区间与n互质的数的个数减去(1,a-1)区间与n互质的数的个数,那么现在就转化成求(1,m)区间于n

互质的数的个数,如果要求的是(1,n)区间与n互质的数的个数的话,我们直接求出n的欧拉函数值即可,可是这里是行不通的!我们不妨

换一种思路:就是求出(1,m)区间与n不互质的数的个数,假设为num,那么我们的答案就是:m-num!

举一组实例吧:假设m=12,n=30.

第一步:求出n的质因子:2,3,5;

第二步:(1,m)中是n的因子的倍数当然就不互质了(2,4,6,8,10)->n/2  6个,(3,6,9,12)->n/3  4个,(5,10)->n/5  2个。

如果是粗心的同学就把它们全部加起来就是:6+4+2=12个了,那你就大错特错了,里面明显出现了重复的,我们现在要处理的就是如何去掉那些重复的了!

第三步:这里就需要用到容斥原理了,公式就是:n/2+n/3+n/5-n/(2*3)-n/(2*5)-n/(3*5)+n/(2*3*5).

第四步:我们该如何实现呢?我在网上看到有几种实现方法:dfs(深搜),队列数组,位运算三种方法都可以!上述公式有一个特点:n除以奇数个数相乘的

时候是加,n除以偶数个数相乘的时候是减。我这里就写下用队列数组如何实现吧:我们可以把第一个元素设为-1然后具体看代码如何实现吧!

#include<cstdio>
int j,a[1000];
void init(int n)
{
    int i;
    j=0;
    for(i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            a[j++]=i;
            while(n%i==0)
                n/=i;
        }
    }
        if(n>1) a[j++]=n;
}
__int64 query(__int64 n)
{
    __int64 b[10000],i,m,k,t=0,sum=0;
    b[t++]=-1;
    for(i=0;i<j;i++)
    {
        k=t;
        for(m=0;m<k;m++)
        {
            b[t++]=b[m]*a[i]*(-1);
        }
    }
    for(i=1;i<t;i++)
        sum+=n/b[i];
    return sum;
}
int main()
{
    int n,i,t;
    __int64 x,y,m;
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        scanf("%I64d%I64d%d",&x,&y,&n);
        init(n);
        m=y-query(y)-(x-1-query(x-1));
        printf("Case #%d: %I64d\n",i,m);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值