2339: [HNOI2011]卡农

Description

img


首先去除顺序不同算一种的麻烦,就是最后答案除以总片段数\(2^m-1\)

\(f_i\)表示安排\(i\)个片段的合法种类

那么对于任何一个包含\(i-1\)个片段的序列(除了发\(f_{i-1}\)的那几个合法序列)都能再找到唯一一个片段使得整个序列变为合法序列(那种和旋是基数个就选上)。但是还有一种特例就是可能这个新选的片段已经在序列里了,这种情况下把这两个相同的片段去掉肯定还是合法序列啊,就是\(f_{i-2}\)

所以总柿子就是\[f_i= A_{2^m-1}^{i-1}-f_{i-1}-f_{i-2}*(i-1)*(2^m+1-i)\]


#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define M 100000007
using namespace std;

LL m,n,j,k,a[1000001],f[1000001],t=1,g=1,d=1;

LL pow(LL x,LL y) 
{
    LL z=1;
    for(y;y>1;y>>=1,x=x*x%M) if(y&1) z=z*x%M;
    return x*z%M;
}

int main()
{
    a[0]=f[0]=1;
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) t=t*2%M;  t=(t-1+M)%M;
    for(int i=1;i<=m;i++) a[i]=a[i-1]*((t-i+1+M)%M)%M,d=d*i%M;
    for(int i=2;i<=m;i++) f[i]=((a[i-1]-f[i-1]+M-f[i-2]*(i-1)%M*(t-i+2+M)%M)%M+M)%M;
    printf("%lld",f[m]*pow(d,M-2)%M);
}

猜你喜欢

转载自www.cnblogs.com/ZUTTER/p/10206298.html