• 【bzoj3930】[CQOI2015]选数 【莫比乌斯反演】【杜教筛】


    题目传送门
    题意:求从区间[L,H]LH为整数)中选取N个整数,使它们的gcdK的方案总数模1000000007的值。
    题解:我们令l=L1Kr=HK。则原问题等价于求从区间[l,r]中选取N个整数,使它们的gcd1的方案总数模1000000007的值。
    我们令F(i)为选数的gcd为i的倍数的方案总数,则显然F(i)=(rili)N
    我们令f(i)为选数的gcd为i的方案总数,则显然F(i)=i|df(d)
    莫比乌斯反演可得f(i)=i|dμ(di)F(d)
    把i=1带入,得f(1)=d=1rμ(d)(rdld)N
    于是这个式子我们可以先杜教筛求出μ的前缀和,再分块计算。
    杜教筛是什么?
    杜教筛点这里
    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1000005,M=1000033;
    const ll mod=1000000007;
    int n,k,l,r,p[N];
    ll ans,mu[N];
    bool vis[N];
    ll fastpow(ll a,ll x){
        a%=mod;
        ll res=1;
        while(x){
            if(x&1){
                res=res*a%mod;
            }
            x>>=1;
            a=a*a%mod;
        }
        return res;
    }
    struct Hashset{
        int cnt,head[M],to[M],nxt[M];
        ll v[M];
        bool count(int f){
            int x=f%M;
            for(int i=head[x];i;i=nxt[i]){
                if(to[i]==f){
                    return true;
                }
            }
            return false;
        }
        ll get(int f){
            int x=f%M;
            for(int i=head[x];i;i=nxt[i]){
                if(to[i]==f){
                    return v[i];
                }
            }
        }
        void set(int f,ll val){
            int x=f%M;
            to[++cnt]=f;
            nxt[cnt]=head[x];
            v[cnt]=val;
            head[x]=cnt;
        }
    }s;
    ll solve(int n){
        if(n<=1000000){
            return mu[n];
        }
        if(s.count(n)){
            return s.get(n);
        }
        ll res=1;
        for(int i=2,last;i<=n;i=last+1){
            last=n/(n/i);
            res-=solve(n/i)*(last-i+1)%mod;
            res%=mod;
        }
        s.set(n,res);
        return res;
    }
    int main(){
        scanf("%d%d%d%d",&n,&k,&l,&r);
        l=(l-1)/k;
        r/=k;
        if(!r){
            puts("0");
            return 0;
        }
        mu[1]=1;
        for(int i=2;i<=1000000;i++){
            if(!vis[i]){
                p[++p[0]]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=p[0]&&i*p[j]<=1000000;j++){
                vis[i*p[j]]=true;
                if(i%p[j]){
                    mu[i*p[j]]=-mu[i];
                }else{
                    break;
                }
            }
        }
        for(int i=2;i<=1000000;i++){
            mu[i]+=mu[i-1];
            mu[i]%=mod;
        }
        for(int i=1,last;i<=r;i=last+1){
            if(l/i){
                last=min(r/(r/i),l/(l/i));
            }else{
                last=r/(r/i);
            }
            ans+=fastpow(r/i-l/i,n)*(solve(last)-solve(i-1))%mod;
            ans%=mod;
        }
        printf("%lld
    ",(ans+mod)%mod);
        return 0;
    }
  • 相关阅读:
    hdu5358 推公式+在一个区间内的尺取+枚举法
    poj3349 散列表(hash)
    hdu3282 链表或者对顶堆
    hdu5178 尺取
    hdu5672 尺取
    hdu3244完全背包+二分答案 留坑
    hdu5256 二分求LIS+思维
    hdu5646数学构造+二分
    hdu4190 二分答案
    Python中Scapy网络嗅探模块的使用
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476864.html
Copyright © 2020-2023  润新知