bzoj2339 [HNOI2011]卡农
Description
正解:数学。
这种数学题自己根本就想不到啊。。
首先我们可以把片段看成有序的,只要最后除一下$m!$就行了。
然后我们考虑$m$个片段的所有情况(包括不合法的)为$A_{2^{n}-1}^{m-1}$。
当前$m-1$个片段确定以后,第$m$个片段肯定也能确定了。
上面考虑到了每个数必须出现偶数次,但是没有考虑第$m$个片段是空集和与前$m-1$个片段重复的情况。
那么我们设$f[m]$表示$m$个片段的合法情况,考虑怎么去掉空集和重复的情况。
当第$m$个片段是空集时,显然,这是因为前$m-1$个片段已经是合法情况,所以才有这种情况,那么减去$f[m-1]$就行了。
当第$m$个片段与前面某一片段重复时,我们可以枚举这是第几个片段,总共有$m-1$个这样的片段。
于是拿掉这两个片段以后,剩下的$m-2$个片段又是合法情况了,再考虑这两个片段的方案数,可以得到我们需要减去的就是$(m-1)*f[m-2]*[2^{n}-1-(i-2)]$。
于是这道题我们就做完了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define rhl (100000007) 6 #define N (1000010) 7 8 using namespace std; 9 10 ll f[N],g[N],bin,fac,n,m; 11 12 il ll qpow(RG ll a,RG ll b){ 13 RG ll ans=1; 14 while (b){ 15 if (b&1) ans=ans*a%rhl; 16 a=a*a%rhl,b>>=1; 17 } 18 return ans; 19 } 20 21 int main(){ 22 #ifndef ONLINE_JUDGE 23 freopen("canon.in","r",stdin); 24 freopen("canon.out","w",stdout); 25 #endif 26 cin>>n>>m,bin=(qpow(2,n)-1+rhl)%rhl,g[0]=fac=1; 27 for (RG ll i=1;i<=m;++i) g[i]=g[i-1]*(bin-i+1+rhl)%rhl,fac=fac*i%rhl; 28 for (RG ll i=3;i<=m;++i) 29 f[i]=(g[i-1]-f[i-1]+rhl-(i-1+rhl)*f[i-2]%rhl*(bin-i+2+rhl)%rhl+rhl)%rhl; 30 cout<<f[m]*qpow(fac,rhl-2)%rhl; return 0; 31 }