bzoj 3930: [CQOI2015]选数【快速幂+容斥】

参考:https://www.cnblogs.com/iwtwiioi/p/4986316.html
注意区间长度为1e5级别。
则假设n个数不全相同,那么他们的gcd小于最大数-最小数,证明:则gcdk2−gcdk1=gcd(k2−k1)>d
所以特判一下全相等的情况就行利润
然后把区间除以k,这样问题就转成了找gcd==1,设f[i]为gcd为i的方案数。从大到小枚举约数,快速幂计算选取选取情况,然后减去约束的倍数的f(容斥)

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005,mod=1e9+7;
int n,k,l,r,len,p,f[N];
int ksm(int a,int b)
{
    int r=1;
    while(b)
    {
        if(b&1)
            r=1ll*r*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return r;
}
int main()
{
    scanf("%d%d%d%d",&n,&k,&l,&r);
    if(l<=k&&r>=k)
        p=1;
    l=(l-1)/k,r=r/k,len=r-l;
    for(int i=len;i>=1;i--)
    {
        int x=l/i,y=r/i;
        f[i]=(ksm(y-x,n)-y+x+mod)%mod;
        for(int j=i*2;j<=len;j+=i)
            f[i]=((f[i]-f[j])%mod+mod)%mod;
    }
    printf("%d\n",f[1]+p);
    return 0;
}
posted @ 2018-04-25 19:35  lokiii  阅读(107)  评论(0编辑  收藏  举报