【BZOJ2339】【HNOI2011】卡农

""

题解:

  首先用二进制表示每个音阶是否使用,那么共有$2^{n}-1$(空集不可行)种片段,用$a_{i}$来表示每个片段,问题就是求满足$a_{1}\left (xor\right)a_{2}\left (xor\right)......\left (xor\right)a_{m}==0\&\&a_{i}!=a_{j},1<=i<j<=m$的方案数,我们用$f_{i}$表示片段数为i时,且满足前面式子的答案。

  那么首先我们在选取i个片段时,必然是由前i-1个片段决定的,所以共有$A_{2^{n}-1}^{i-1}$种选取方案。其中若i-1个时已满足其异或和为0,那么此时是不合法的,所以需要减去$f_{i-1}$,考虑出现重复的情况,因为出现了重复,又有异或的逆运算就是本身,这也就意味着除去两个重复的片段的i-2个片段已经满足其异或和为0,而这个重复的片段在i-1个片段中的位置有i-1种,而这个重复的片段的值又可以在除去i-2个片段的集合中任意选取。

  所以得到递推式:

  $$f_{i}=A_{2^{n}-1}^{i-1}-f_{i-1}-f_{i-2}*(2^{n}-1-i+2)*(i-1)$$

  又由于不允许有重复,在最后除去$m!$即可。

 

 1 #include<cstdio>
 2 typedef long long ll;
 3 const ll mod=100000007;
 4 const int N=1000100;
 5 ll n,m;
 6 ll powmod(ll a,ll b){
 7     ll ans=1;
 8     a%=mod;
 9     for(;b;b>>=1,a=a*a%mod)
10         if(b&1) ans=ans*a%mod;
11     return ans;
12 }
13 ll tot;
14 ll jie;
15 ll fac[N];
16 inline void init(){
17     fac[0]=1;
18     for(ll i=1;i<=m;i++)    
19         fac[i]=fac[i-1]*(tot-i+1)%mod;
20 }
21  
22 ll f[N];
23 int main(){
24     scanf("%lld%lld",&n,&m);
25     tot=powmod(2LL,n);
26     tot--;
27     if(tot<0)   tot+=mod;
28     init();
29     for(ll i=3;i<=m;i++){
30         f[i]=(fac[i-1]-f[i-1])%mod-f[i-2]*(i-1)%mod*(tot-i+2)%mod;
31         f[i]%=mod;
32     }
33     ll tt=1;
34     for(ll i=1;i<=m;++i)
35         tt=tt*i%mod;
36     tt=powmod(tt,mod-2);
37     printf("%lld\n",(f[m]*tt%mod+mod)%mod);
38 }

 

posted @ 2017-08-26 08:44  Troywar  阅读(197)  评论(0编辑  收藏  举报