• 【BZOJ3930】[CQOI2015] 选数(容斥)


    点此看题面

    大致题意: 让你求出在区间([L,H])间选择(n)个数时,有多少种方案使其(gcd)(K)

    容斥

    原以为是一道可怕的莫比乌斯反演

    但是,数据范围中有这样一句话:(H-Lle10^5)

    于是,它就变成了一道可以用容斥乱搞的题目。

    大致思路

    首先,我们将(L)(H)分别除以(K)(注意(L)向上取整,(H)向下取整,这应该还是比较好理解的)。

    然后我们在([1,H-L])之间枚举(i),假设(x)表示([L,H])区间内选出(i)的倍数的个数,则选择(n)个数使得这些数全部含有约数(i)的方案数应为(x^n-x)

    那么如何求出最大公约数是(i)的方案数呢?

    很简单,根据容斥原理,全是(i)倍数的方案数中多余的方案数应为最大公约数为(2i,3i,4i,...)的方案数,所以我们可以倒着求一遍,得出答案。

    具体实现详见代码吧。

    代码

    #include<bits/stdc++.h>
    #define MOD 1000000007
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define Dec(x,y) ((x-=(y))<0&&(x+=MOD))
    #define Delta 100000
    using namespace std;
    int n,k,l,r,f[Delta+5];
    inline int quick_pow(int x,int y,register int res=1)//快速幂
    {
        for(;y;x=1LL*x*x%MOD,y>>=1) if(y&1) res=1LL*res*x%MOD;
        return res;
    }
    int main()
    {
        register int i,j,x,y;
        for(scanf("%d%d%d%d",&n,&k,&l,&r),(l+=k-1)/=k,r/=k,i=1;i<=r-l;++i) x=(l+i-1)/i,y=r/i,f[i]=quick_pow(y-x+1,n),Dec(f[i],y-x+1);//求出含有约数i的方案数f[i]
        for(i=r-l;i;--i) for(j=i<<1;j<=r-l;j+=i) Dec(f[i],f[j]);//容斥,求出gcd为i的方案数f[i]
        return printf("%d",f[1]+(l==1)),0;//特判l=1的情况,将f加1
    }
    
  • 相关阅读:
    888. Uncommon Words from Two Sentences
    344. Reverse String
    151. Reverse Words in a String
    557. Reverse Words in a String III
    811. Subdomain Visit Count
    上海市公积金、养老保险、医疗保险转出事宜
    476. Number Complement
    方法重载的条件
    简单工厂模式
    单例模式
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3930.html
Copyright © 2020-2023  润新知