2339: [HNOI2011]卡农
Description
首先去除顺序不同算一种的麻烦,就是最后答案除以总片段数\(2^m-1\)
设\(f_i\)表示安排\(i\)个片段的合法种类
那么对于任何一个包含\(i-1\)个片段的序列(除了发\(f_{i-1}\)的那几个合法序列)都能再找到唯一一个片段使得整个序列变为合法序列(那种和旋是基数个就选上)。但是还有一种特例就是可能这个新选的片段已经在序列里了,这种情况下把这两个相同的片段去掉肯定还是合法序列啊,就是\(f_{i-2}\)
所以总柿子就是$$f_i= A_{2m-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);
}