排列 [HNOI2011]卡农

来源:互联网 发布:5 6岁 书 知乎 编辑:程序博客网 时间:2024/04/27 16:15

问题 A: [HNOI2011]卡农
时间限制: 1 Sec 内存限制: 128 MB
题目描述
这里写图片描述
共有2^n-1种片段组合方式。设数字i出现次数ai,选i个片段是合法总方案数为fi。
这里我们先按不同排列方式为不同情况。
那么对于A(2^n-1,i-1)就是i个位置上有i-1个位置上放上了片段,有两种情况,
1,这i-1个片段已满足要求,不合法。
2,这i-1个片段不满足要求,那么有唯一一个片段使之合法。
但是考虑放i-2个片段时是满足的,加了任意一个其他片段后是i-1个,之后又加了一个相同的片段使之满足,那他就重复了,不合法。所以要把这两种情况去掉。
第一种减去fi-1,第二种减fi-2*(i-1)*(2^n-1-(i-2))。
那我解释一下,对于每种放i-2个时的满足情况,可以放剩余2^n-1-(i-2)个片段中的任一个,并且有i-1个位置可以放。那现在再结合上面的看。
最后除以m!(因为不同排列算一个)

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define mod 100000007#define N 1000005using namespace std;ll n,m,A[N],f[N],xp=1,ans=1;inline ll cheng(ll x,ll n){    ll s=1;x%=mod;    while(n)    {        if(n&1)s=s*x%mod;        x=x*x%mod;        n/=2;    }    return s;}int main(){   // freopen("canon.in","r",stdin);//  freopen("canon.out","w",stdout);    cin>>n>>m;A[0]=1;f[0]=1;    xp=cheng(2ll,n);xp--;if(xp<0)xp+=mod;    for(int i=1;i<=m;i++)A[i]=A[i-1]*(xp-i+1)%mod;    for(int i=3;i<=m;i++)f[i]=(A[i-1]-f[i-1])%mod-(f[i-2]*(xp-i+2)%mod*(i-1))%mod,f[i]%=mod;    for(int i=2;i<=m;i++)ans=(ans*i)%mod;    ans=cheng(ans,mod-2);//求逆元    ans=(ans*f[m]%mod+mod)%mod;    cout<<ans;}
原创粉丝点击