排列 [HNOI2011]卡农

问题 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 1000005
using 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;
}
posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(124)  评论(0编辑  收藏  举报