南京理工校赛 C count_prime

上次的广工业刚刚出过容斥的题,然而当初那道题问学长,学长说不会,自己看别人博客,博客里说了下是容斥原理,剩下的只有代码,看到别人写得那么长的代码(其实也不算长,只是没用头文件10+行,看着就头疼,唉~~~~)自己看时连容斥原理都没搞懂,更别提看代码了,总觉得很难。结果这次比赛又遇到了,懵逼~~~           刚好今天没比赛,顺手补补题,把容斥原理搞懂了,刚把广工的容斥搞懂,又把这道题给AC了, 唉~好久没一次AC了,这次一把A,好爽大笑,      这道题只需要将n分解出的质因数存在数组里,然后两遍容斥dfs分别求出总区间与n非质的数,以及前一段区间与n非质的数,接着中间区间的数字个数再减去前面的数,就A了~~~

count_prime

Time Limit: 1000ms

Memory Limit: 65536KB

Description

给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的。

Input

第一行输入一个整数T(1 <= T <= 100),表示T组测试数据。接下来T行,每行3个整数a,b,n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。

Output

输出一个整数表示 和n互质 的数的个数。

Sample Input

2
1 10 2
3 10 5

Sample Output

5
6

代码:

#include<stdio.h>
#define ll long long
ll a[40],b[40],s1,s2,k,x,y;
ll gcd(ll aa,ll bb)
{
 return bb?gcd(bb,aa%bb):aa;
}
ll lcm(ll aa,ll bb)
{
 return aa/gcd(aa,bb)*bb;
}
void dfs(ll qi,ll shu,ll mo)
{
    if(qi==k)
    {
        if(mo)
        {
            if(mo&1)
                s1+=y/shu;
            else
                s1-=y/shu;
        }
        return;
    }
    dfs(qi+1,shu,mo);
    shu=lcm(shu,a[qi]);
    if(shu<=y)
     dfs(qi+1,shu,mo+1);
}
void dfss(ll qi,ll shu,ll mo)
{
    if(qi==k)
    {
        if(mo)
        {
            if(mo&1)
                s2+=(x-1)/shu;
            else
                s2-=(x-1)/shu;
        }
        return;
    }
    dfss(qi+1,shu,mo);
    shu=lcm(shu,a[qi]);
    if(shu<=x-1)
     dfss(qi+1,shu,mo+1);
}

int main()
{
    int N;
    scanf("%d",&N);
    while(N--)
    {
        ll i,j,n;
        scanf("%lld%lld%lld",&x,&y,&n);
        k=0,s1=0,s2=0;
        for(i=2; i*i<=n; i++)
        {
            if(n%i==0)
            {
                while(n%i==0)
                    n/=i;
                a[k++]=i;
            }
        }
        if(n>1)
         a[k++]=n;
        dfs(0,1,0);
        dfss(0,1,0);
        printf("%lld\n",y-x+1-(s1-s2));
    }
}



你可能感兴趣的:(容斥原理)