hdu4135欧拉,容斥

来源:互联网 发布:java ftp client 编辑:程序博客网 时间:2024/05/18 00:01

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;}
0 0
原创粉丝点击