首页 > 代码库 > BZOJ 3930 选数

BZOJ 3930 选数

莫比乌斯反演+杜教筛。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<map>#define maxn 10000000#define mod 1000000007#define inf 0x7f7f7f7f7f7f7f7fLLusing namespace std;long long n,k,l,r,miu[maxn+50],prime[maxn+50],top=0,ans=0;bool vis[maxn+50];map <long long,long long> mp;void linear_shaker(){    miu[1]=1;    for (long long i=2;i<=maxn;i++)    {        if (!vis[i])        {            prime[++top]=i;            miu[i]=-1;        }        for (long long j=1;j<=top && i*prime[j]<=maxn;j++)        {            vis[i*prime[j]]=true;            if (i%prime[j]==0)            {                miu[i*prime[j]]=0;                break;            }            else miu[i*prime[j]]=-miu[i];        }    }    for (long long i=1;i<=maxn;i++)        miu[i]+=miu[i-1];}long long f_pow(long long a,long long b){    long long base=a,ans=1;    while (b)    {        if (b&1) ans=(ans*base)%mod;        base=(base*base)%mod;        b>>=1;    }    return ans;}long long ask(long long x){    if (x<=maxn) return miu[x];    if (mp.find(x)!=mp.end()) return mp[x];    long long pos=2,last=1,ret=0;    while (pos<=x)    {        last=x/(x/pos);        ret+=(last-pos+1)*ask(x/pos);        pos=last+1;    }     return mp[x]=1-ret;}int main(){    scanf("%lld%lld%lld%lld",&n,&k,&l,&r);    linear_shaker();     long long pos=1,last=0;    while (pos<=(r/k))    {        long long ret1=(r/k)/((r/k)/pos),ret2;        if (!((l-1)/(k*pos))) ret2=inf;        else ret2=((l-1)/k)/(((l-1)/k)/pos);        last=min(ret1,ret2);        ret1=(ask(last)-ask(pos-1));ret2=f_pow(r/(k*pos)-(l-1)/(k*pos),n);        ans+=((ask(last)-ask(pos-1))*f_pow(r/(k*pos)-(l-1)/(k*pos),n))%mod;        if (ans<mod) ans=(ans+mod)%mod;        pos=last+1;    }    printf("%lld\n",(ans+mod)%mod);    return 0;}

 

BZOJ 3930 选数