zoukankan      html  css  js  c++  java
  • [CQOI2015]选数

    [CQOI2015]选数

    从[L,H]中可重复地选出N个数,问其gcd等于K的方案(mod 10^9+7),1<=N,K<=109,1<=L<=H<=109,H-L<=10^5。

    法一:直接

    转换为Mobius问题,不难有

    [ans=sum_{i_1=L}^Hsum_{i_2=L}^H...sum_{i_N=L}^H(gcd(i_1,i_2,...,i_N)==k) ]

    于是设

    [f(k)=sum_{i_1=L}^Hsum_{i_2=L}^H...sum_{i_n=L}^H(gcd(i_1,i_2,...,i_n)==k) ]

    [F(k)=sum_{i_1=L}^Hsum_{i_2=L}^H...sum_{i_N=L}^H(k|gcd(i_1,i_2,...,i_N))=([frac{H}{k}]-[frac{L-1}{k}])^N ]

    由Mobius反演定理代入有

    [ans=sum_{k|d}([frac{H}{d}]-[frac{L-1}{d}])^Nmu(d/k)= ]

    [sum_{d=1}^{[H/k]}([frac{H}{dk}]-[frac{L-1}{dk}])^Nmu(d) ]

    显然左式可以整除分块,而至于后式只需要快速维护其前缀和,注意到N很大,于是用杜教筛优化即可。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define ll long long
    #define control 6000000
    #define yyb 1000000007
    using namespace std;
    template<class f1,class f2>
    struct chain{
        chain*next;f1 x;f2 y;
    };
    template<class f1,class f2,class f3,f3 key>
    struct unordered_map{
        chain<f1,f2>*head[key],*p;
        il void insert(f1 x,f2 y){
            p=new chain<f1,f2>,p->x=x,p->y=y;
            x%=key,p->next=head[x],head[x]=p;
        }
        il chain<f1,f2>* find(f1 x){
            for(p=head[x%key];p!=NULL;p=p->next)
                if(p->x==x)return p;
            return NULL;
        }
    };
    bool check[control+1];
    int prime[600000],pt,mb[control+1];
    il void prepare(int);
    il int djs(int),pow(int,int),min(int,int);
    int main(){
        int n,k,l,h,i,j,ans(0);
        scanf("%d%d%d%d",&n,&k,&l,&h);
        h/=k,(--l)/=k,prepare(control);
        for(i=1;i<=h;i=j+1){
            j=h/(h/i);if(l/i)j=min(j,l/(l/i));
            (ans+=(ll)(djs(j)-djs(i-1))*pow(h/i-l/i,n)%yyb)%=yyb;
        }printf("%d",(ans+yyb)%yyb);
        return 0;
    }
    il int min(int a,int b){
        return a<b?a:b;
    }
    il int pow(int x,int y){
        int ans(1);while(y){
            if(y&1)ans=(ll)ans*x%yyb;
            x=(ll)x*x%yyb,y>>=1;
        }return ans;
    }
    unordered_map<int,int,int,999983>m;
    il int djs(int n){
        if(n<=control)return mb[n];
        if(m.find(n)!=NULL)return m.find(n)->y;int i,j,ans(1);
        for(i=2;i<=n;i=j+1)j=n/(n/i),ans-=(j-i+1)*djs(n/j);
        return m.insert(n,ans),ans;
    }
    il void prepare(int n){
        int i,j;check[1]|=mb[1]|=true;
        for(i=2;i<=n;++i){
            if(!check[i])prime[++pt]=i,mb[i]=-1;
            for(j=1;j<=pt&&prime[j]<=n/i;++j){
                check[i*prime[j]]|=true;
                if(!(i%prime[j]))break;
                mb[i*prime[j]]=~mb[i]+1;
            }
        }for(i=1;i<=n;++i)mb[i]+=mb[i-1];
    }
    
    

    法二:优化

    思路一:


    [gcd(a,b)leq|a-b|(a eq b) ]

    证明:
    (|x-y|=|k_1gcd(x,y)-k_2gcd(x,y)|=gcd(x,y)|k_1-k_2|)

    故得证。


    注意到(H-Lleq10^5),于是猜测gcd范围应在里面,于是我们有结论(gcd(a,b)leq|a-b|(a eq b)),所以只要对a,b相同的情况单独讨论,而显然这种方案有且仅有一种,只要看其是否落在([L,H])内即可,于是接下来就可以直接对法一进行优化了,但是注意该结论一定是不存在全相同对数。

    思路二:

    而注意到问题比较简单,而有可以使用Mobius反演,于是我们考虑容斥,于是令(L=[L-1]/k+1,H/=k),接下来问题变成只要对互质对数考虑即可,所以设(D(n)=([frac{H}{n}]-[frac{L-1}{n}])^N-[frac{H}{n}]+[frac{L-1}{n}]),表示有公约数n的互质的不全相同的对数,根据容斥原理,我们有

    [ans=sum_{d=1}^{|H-L|}mu(d)D(d) ]

    进行整除分块即可,注意后面全相同对数的情况,因为这也是一种方案。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define ll long long
    #define yyb 1000000007
    using namespace std;
    bool check[100001];
    int prime[2500],pt,mb[100001];
    il void prepare(int);
    il int pow(int,int),min(int,int);
    int main(){
        int n,k,l,h,l_,i,j,cjx,li,ans(0);
        scanf("%d%d%d%d",&n,&k,&l,&h);
        ++(--l/=k),h/=k,l_=l-1;
        li=h-l,prepare(li);
        for(i=1;i<=li;i=cjx+1){
            j=h/i-l_/i,cjx=h/(h/i);
            if(l_/i)cjx=min(cjx,l_/(l_/i));
            (ans+=(ll)(mb[cjx]-mb[i-1])*(pow(j,n)-j)%yyb)%=yyb;
        }if(l==1)++ans;printf("%d",(ans+yyb)%yyb);
        return 0;
    }
    il int min(int a,int b){
        return a<b?a:b;
    }
    il int pow(int x,int y){
        int ans(1);while(y){
            if(y&1)ans=(ll)ans*x%yyb;
            x=(ll)x*x%yyb,y>>=1;
        }return ans;
    }
    il void prepare(int n){
        int i,j;check[1]|=mb[1]|=true;
        for(i=2;i<=n;++i){
            if(!check[i])prime[++pt]=i,mb[i]=-1;
            for(j=1;j<=pt&&prime[j]<=n/i;++j){
                check[i*prime[j]]|=true;
                if(!(i%prime[j]))break;
                mb[i*prime[j]]=~mb[i]+1;
            }
        }for(i=1;i<=n;++i)mb[i]+=mb[i-1];
    }
    
    
  • 相关阅读:
    sublime生成html快捷标签布局
    vue.js选项卡动态组件
    textarea内容限制字数
    60s验证等待
    vue.js显示隐藏
    CSS强制性换行
    Ultra Pull To Refresh下拉刷新
    Open经验库网址
    Fresco实例
    解决LinearLayout中控件不能居右对齐
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10795462.html
Copyright © 2011-2022 走看看