标签:技术 mod 允许 二进制 pre img i++ typedef void
首先用二进制表示每个音阶是否使用,那么共有$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 }
标签:技术 mod 允许 二进制 pre img i++ typedef void
原文地址:http://www.cnblogs.com/Troywar/p/7434460.html