1. 程式人生 > >2339: [HNOI2011]卡農

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);
}