BZOJ 3930 选数

Posted on 2016-09-19 17:56  ziliuziliu  阅读(125)  评论(0编辑  收藏  举报

莫比乌斯反演+杜教筛。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxn 10000000
#define mod 1000000007
#define inf 0x7f7f7f7f7f7f7f7fLL
using 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;
}