题解:
首先用二进制表示每个音阶是否使用,那么共有$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 }
时间: 2024-12-28 11:36:14