hdu1695:数论+容斥

题目大意:

求x属于[1,b]和 y属于[1,d]的 gcd(x,y)=k 的方案数

题解:

观察发现 gcd()=k 不好处理,想到将x=x/k,y=y/k 后 gcd(x,y)=1。。

即问题转化为求区间 [1,b/k]和 [1,d/k]的互质数对个数

由于题目规定 (x,y)和(y,x)是同一种,所以我们可以规定 x<y,,然后只需对每一个y求出比他小的即可

公共部分可以通过欧拉函数快速求出。。

非公共部分就不行了。。

所以就分解质因数,用容斥的方法求了

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
#define maxn 100000
int isnotprime[maxn+1];
int num[maxn+1];
int fac[maxn+1][30];
int prime[maxn];
int euler[maxn+1];
int np;
int a,b,c,d,k,n,m;
long long ans;
void setprime()
{
    np=0;
    memset(isnotprime,0,sizeof(isnotprime));
    for(int i=2;i<=1000;i++)
    {
        if(!isnotprime[i])
           prime[np++]=i;
        for(int j=0;j<np&&prime[j]*i<=1000;j++)
        {
            isnotprime[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
}
void findfac(int x)
{
    num[x]=0;
    int p=x;
    for(int i=0;i<np;i++)
    {
        if(p%prime[i]==0)
        {
            fac[x][num[x]++]=prime[i];
        }
        while(p%prime[i]==0)
        {
            p/=prime[i];
        }
    }
    if(p>1)
    {
        fac[x][num[x]++]=p;
    }
}
void setfac()
{
    for(int i=2;i<=maxn;i++)
    {
        findfac(i);
    }
}
void phi()
{
    for(int i=1;i<=maxn;i++)
        euler[i]=i;
    for(int i=2;i<=maxn;i+=2)
        euler[i]/=2;
    for(int i=3;i<=maxn;i++)
    {
        if(euler[i]==i) //未被筛到。是素数,则用此素数来筛
        {
            for(int j=i;j<=maxn;j+=i)
            {
                euler[j]=euler[j]/i*(i-1);
            }
        }
    }
    return ;
}
void ini()
{
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
}
int iae(int x)
{
    int res=0;
    int cur,tmp;
    for(int i=1;i<(1<<num[x]);i++)
    {
        cur=1;
        tmp=0;
        for(int j=0;j<num[x];j++)
        {
            if(i&(1<<j))
            {
                cur*=fac[x][j];
                tmp++;
            }
        }
        if(tmp&1)
        {
            res+=m/cur;
        }
        else
        {
            res-=m/cur;
        }
    }
    return m-res;
}
int cas=1;
void solve()
{
    printf("Case %d: ",cas++);
    if(k==0)
    {
        puts("0");
        return;
    }
    m=min(b/k,d/k);
    n=max(b/k,d/k);
    ans=0;
    for(int i=1;i<=m;i++)
    {
        ans+=euler[i];
    }
    for(int i=m+1;i<=n;i++)
    {
        ans+=iae(i);
    }
    printf("%I64d\n",ans);
}
int main()
{
    setprime();
    setfac();
    phi();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ini();
        solve();
    }
    return 0;
}

 

posted @ 2014-11-13 21:53  PlasticSpirit  阅读(191)  评论(0编辑  收藏  举报