hdu4135欧拉,容斥

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

题意:求[A,B]中与n互素的个数。—-来自芷水的文章
转化一下思路:
1.
求[A,B]中的等于[1,B]中与互素的个数减[1,A-1]中与n互素的个数,
这就转化为[1,K]了。
2.
求[1,K]中与N互素的个数又转化为 K 减去 [1,K]中与N满足gcd(N,k1)>1的个数。
接下来,就要求N的素因子了。为什么是素因子??
因为每一个数都能有素因子组成。
求素因子的方法和求欧拉的方法是一样的。
有两种方法,一种适合于单点求取,数字比较大的时候更好。
一种适合于打表求取,适用数字相对较的情况。
3.
求解的过程中会遇到重复的问题。
举一个例子 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 <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL q[100001],f[100],len;
void eular(LL n)//求素因子存在f中
{
    len=0;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            while(n%i==0)
            n/=i;
            f[++len]=i;
        }
    }
    if(n!=1)
    f[++len]=n;
}
LL capticy(LL num)//容斥原理
{
    LL t=0,k,sum=0;
    q[t++]=-1;
    for(int i=1;i<=len;i++)
    {
        k=t;
        for(int j=0;j<k;j++)
        q[t++]=-1*q[j]*f[i];
    }
    for(int i=1;i<t;i++)
    sum=sum+num/q[i];
    return sum;
}
int main()
{int t;
 LL a,b,n,ans;
 cin>>t;
 for(int i=1;i<=t;i++)
 {ans=0;
     cin>>a>>b>>n;
     eular(n);
     ans=(b-capticy(b))-(a-1-capticy(a-1));
     printf("Case #%d: %lld\n",i,ans);
 }
    return 0;
}

位运算:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>

using namespace std;

long long a,b,n;
vector<long long> vt;

{
    vt.clear();
    long long i,j;
    for(i=2;i*i<=n;i++)     //对n进行素数分解
        if(n%i==0)
        {
            vt.push_back(i);
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        vt.push_back(n);

    long long sum=0,val,cnt;
{  //用二进制来1,0来表示第几个素因子是否被用到,如m=3,三个因子是2,3,5,则i=3时二进制是011,表示第2、3个因子被用到
        val=1;
        cnt=0;
        for(j=0;j<vt.size();j++)
            if(i&(1<<j))
            {       //判断第几个因子目前被用到 
                val*=vt[j];
                cnt++;
            }
        if(cnt&1)       //容斥原理,奇加偶减
            sum+=x/val;
        else
            sum-=x/val;
    }
    return x-sum;
}

int main(){

    //freopen("input.txt","r",stdin);

    int t,cases=0;
    scanf("%d",&t);
    while(t--)
    {
        cin>>a>>b>>n;
        cout<<"Case #"<<++cases<<": "<<solve(b,n)-solve(a-1,n)<<endl;
    }
    return 0;
}

你可能感兴趣的:(hdu4135欧拉,容斥)