BZOJ3930: [CQOI2015]选数

来源:互联网 发布:中国厕所文化知乎 编辑:程序博客网 时间:2024/04/19 08:58

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


一开始对着题目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<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing 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;}
0 0