题目描述:
题目分析:
注意到如果我们确定了前
n
−
1
n-1
n−1个片段的音阶集合,那么第
n
n
n个就确定了。
这样的话,为了方便统计,我们将片段的不同排列计入,最后答案除去
m
!
m!
m!
设
f
[
i
]
f[i]
f[i]表示用
i
i
i个片段,每个音阶次数为偶数的方案数。
从所有的
2
n
−
1
2^n-1
2n−1种片段中选出
i
−
1
i-1
i−1种拿来排列,方案为
A
2
n
−
1
i
−
1
A_{2^n-1}^{i-1}
A2n−1i−1
不合法的情况只会有两种:
- 前 i − 1 i-1 i−1个片段已经满足偶数条件,即第 i i i个片段为空,这样的数量是 f [ i − 1 ] f[i-1] f[i−1]
- 前 i − 1 i-1 i−1个片段中有一个与第 i i i个片段相同,那么剩下的 i − 2 i-2 i−2个片段就满足偶数条件,第 i i i个片段可以为剩下的 2 n − 1 − ( i − 2 ) 2^n-1-(i-2) 2n−1−(i−2)中的任意一个,与 i i i相同的片段可以是前 i − 1 i-1 i−1中的任意一个,这样的数量是 f [ i − 2 ] ∗ ( 2 n − 1 − ( i − 2 ) ) ∗ ( i − 1 ) f[i-2]*(2^n-1-(i-2))*(i-1) f[i−2]∗(2n−1−(i−2))∗(i−1)
所以DP转移方程就是
f
[
i
]
=
A
2
n
−
1
i
−
1
−
f
[
i
−
1
]
−
f
[
i
−
2
]
∗
(
2
n
−
1
−
(
i
−
2
)
)
∗
(
i
−
1
)
f[i]=A_{2^n-1}^{i-1}-f[i-1]-f[i-2]*(2^n-1-(i-2))*(i-1)
f[i]=A2n−1i−1−f[i−1]−f[i−2]∗(2n−1−(i−2))∗(i−1)
初状态
f
[
0
]
=
1
f[0]=1
f[0]=1
Code:
#include<cstdio>
#define maxn 1000005
using namespace std;
const int mod = 1e8+7;
int n,m,f[maxn];
inline int Pow(int a,int b){
int s=1;
for(;b;b>>=1,a=1ll*a*a%mod) b&1&&(s=1ll*s*a%mod);
return s;
}
int main()
{
scanf("%d%d",&n,&m);
int Pw=Pow(2,n)-1,A=Pw,Fac=1;
f[0]=1;
for(int i=2;i<=m;A=1ll*A*(Pw-i+1)%mod,Fac=1ll*Fac*i%mod,i++)
f[i]=(A-f[i-1]-1ll*f[i-2]*(i-1)%mod*(Pw-i+2))%mod;
printf("%d\n",1ll*(f[m]+mod)*Pow(Fac,mod-2)%mod);
}