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 }

 

posted @ 2017-09-15 14:31  wfj_2048  阅读(249)  评论(0编辑  收藏  举报