2339: [HNOI2011]卡農
阿新 • • 發佈:2019-01-01
Description
首先去除順序不同算一種的麻煩,就是最後答案除以總片段數\(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); }