hdu 1695 两个区间中互素的个数 (容斥)

来源:互联网 发布:ui切图用什么软件 编辑:程序博客网 时间:2024/06/03 14:36

题意是,【1,l】,【1,r】之间个数一个数两个数的最大公约数等于k  求有多少这样的数对。

设x是在【1,l】中取的数,y是在【1,r】中取的数。

x =a*k  ,y=b*k ,k为最大公约数, 所以a与b互素,问题转换为区间(1,l/k)(1  ,  r/k)中有多少互素的数对。

容斥原理在这里求的是 i 在(1,l/k)中与i不互素的个数。例如  1到10中能被2,3整除的个数为 10 / 2+10 / 3 -10 / 6.

 

#include<cstdio>#include<cstring>#include<iostream>using namespace std;#define ll long longconst int N=100005;ll phi[N];//前n项欧拉函数的和int num[N],p[N][25];//num【i】为i的素因子的个数void get_prime()   //p【i】【】表示i的素因子{    phi[1]=1;    int i,j;    for(i=2;i<N;i++)    {        if(!phi[i])        {            for(j=i;j<N;j+=i)            {                if(!phi[j]) phi[j]=j;                phi[j]=phi[j]/i*(i-1);                p[j][num[j]++]=i;            }        }        phi[i]+=phi[i-1];    }}int dfs(int id,int l,int now)//容斥求与l不互素的个数{    int ans=0;    for(int i=id;i<num[now];i++)        ans+=l/p[now][i]-dfs(i+1,l/p[now][i],now);    return ans;}int main(){    get_prime();    int ncase,l,r,k;    scanf("%d",&ncase);    for(int i=1;i<=ncase;i++)    {        scanf("%d%d%d%d%d",&l,&l,&r,&r,&k);        printf("Case %d: ",i);        if(k==0){ puts("0");continue;}        if(l>r) swap(l,r);        l/=k; r/=k;        ll ans=phi[l];        for(int j=l+1;j<=r;j++)           ans+=l-dfs(0,l,j);        printf("%I64d\n",ans);    }    return 0;}

原创粉丝点击