您的位置:首页 > 其它

hdu 1695(GCD) 容斥+欧拉函数

2013-09-10 10:30 381 查看
题目链接:点击打开链接

题目大意:在a~b中找x,c~d中找y。x,y的GCD为k的对数

题目分析:【1】由于xy的最大公约数为k,那么除去x,y其他因数必然互质,问题转化为在b/k和d/k中找x,y互质的对数,这是一一对应的关系

【2】规定b<d,如果暴力求解一定有重复的并且不好删除,那么就一直选取1~d中i与1~min(i,b)判质。

【3】明显在小范围(1~b)就使用欧拉函数:欧拉函数是少于或等于n的数中与n互质的数的数目。φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),但是b+1到d
之间比b大的部分则需要通过容斥原理来求。

先回顾一下容斥原理的内容:

两个集合的容斥关系公式:A∪B = A+B - A∩B (∩:重合的部分)

三个集合的容斥关系公式:A∪B∪C = A+B+C - A∩B - B∩C - C∩A +A∩B∩C

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

【4】欧拉函数+筛选法,借鉴博客:点击打开链接 写的很精彩可以当模板了~~
【5】另外一位大神的方法,没看太懂但是是很好的方法:点击打开链接

题目总结:【1】错误一:

把分解质因数的操作搞混了- -;用到结论1.除2外,其他质数都为奇数2.孪生质数对(p,p+1)

顺便贴下正确代码:

for (int j=2; j<N; j+=2) x[j].push_back(2);  
    for (int i=3; i<N; i+=2)  
        if (!is[i]) {  
            for (int j=i; j<N; j+=i) {  
                is[j] = true;  
                x[j].push_back(i);  
            }  
        }


【2】错误二:直接用筛选法,但是现在要求的EULAR[I] 是要求1~maxn的

for(i=2; i*i<maxn; i=i+2)//
    {
       if(!eular[i])
        {
            for(j=i; j<maxn; j+=i)
            {
                if(eular[j]==0) eular[j]=j;
                eular[j]= eular[j]*(i-1)/i;
                primes[j].push_back(i);
            }

        }eular[i]+=eular[i-1];
    }


最后代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define maxn 100010

using namespace std;
__int64 eular[maxn];
vector<int> primes[maxn];

void init()
{
    int i,j;
    for(i=0; i<maxn; i++)
    {
        primes[i].clear();
        eular[i]=0;
    }
    eular[1]=1;
    for(i=2; i<maxn; i++)
    {
       if(!eular[i])
        {
            for(j=i; j<maxn; j+=i)
            {
                if(eular[j]==0) eular[j]=j;
                eular[j]= eular[j]*(i-1)/i;
                primes[j].push_back(i);
            }

        }eular[i]+=eular[i-1];
    }
}
__int64 dfs(int x ,int b ,int now)
{
    __int64 ans=0;
    for(int i=x;i<primes[now].size();i++)
        ans+=(b/primes[now][i]-dfs(i+1,b/primes[now][i],now));
    return ans;
}
int main()
{
    int t,a,b,c,d,k,i,count=1;
    __int64 ans;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
        if(b>d)   swap(b,d);
        if(k==0)
        {
            printf("Case %d: 0\n",count++);
            continue;
        }
        else
        {
        b/=k , d/=k , ans=eular[b];
        for(i=b+1; i<=d; i++)
               ans+=b - dfs(0,b,i);
        printf("Case %d: %I64d\n",count++,ans);
        }

    }
         return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: