BZOJ3930: [CQOI2015]选数

差不多是条咸鱼了…………


一开始对着题目yy了一个貌似很正确,复杂度不会算的搜索,想了想不是很敢打,往DP想,然后想出了一个看起来很正确的DP,然后挂了….
那想容斥咯………..不会………
那试试反演咯…………..还是不会………
那我到底会什么…………..
看题解好像还是会的



这题做法好多的样子,主要是两类,一类是反演,Orz PoPoQQQ μ 的前缀和处理窝看不懂…………还有一类是容斥,因为区间里选n个不是全部一样的数,有一个易证的结论:他们的gcd不会超过区间长度,
所以现将区间缩为 (l/Kr/K) ,设f[i]表示区间里选n个不是全部一样的数,gcd是i*K的方案数, N 是可以选择的区间的长度,可以得到一个公式
f[i]=NnNi|jf[j] (减 N 是因为要减去全部一样的方案数)
最后要加上全部选一样的数对答案的贡献,那么只有K在可以选择的区间内时才会产生1的贡献



code:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;

const int maxn = 100010;
const ll Mod = 1e9+7;
ll pw(ll x,int k)
{
    x%=Mod;ll ret=1;
    for(ll t=x;k;k>>=1,t=t*t%Mod)
        if(k&1)ret=ret*t%Mod;
    return ret;
}
ll f[maxn];
int n,K,L,H;

int main()
{
    scanf("%d%d%d%d",&n,&K,&L,&H);
    int l=L/K,r=H/K;
    if(L%K) l++;
    int N=r-l+1;
    for(int i=N;i>=1;i--)
    {
        int tr=r/i,tl=l/i;
        if(l%i)tl++;
        if(tl<=tr)
        {
            f[i]=pw(tr-tl+1,n);
            f[i]-=tr-tl+1;
            for(int j=2*i;j<=N;j+=i) f[i]-=f[j];
            f[i]=(f[i]%Mod+Mod)%Mod;
        }
    }
    if(l<=1&&l<=r) f[1]=(f[1]+1)%Mod;
    printf("%lld\n",f[1]);

    return 0;
}

你可能感兴趣的:(BZOJ,数论,容斥原理)