Description
成对成对的人生赢家要去看电影了啦!身为FFF团的骨干,你当然不能坐视不管。但为首的人生赢家小W实在太神辣,你只敢搞一些小动作。
土豪小W包下了电影院的一个包厢,其中有 n 排 m 列座位;相应的,看电影的人共有 nm/2 对。你无力阻止一对人生赢家坐在同一排(这是他们的底线)(m是一个偶数),但你可以想办法让每一对情侣都不相邻。求方案数 mod P 的值。
Input
三个数 n, m , p
Output
每一对情侣在同一排但不相邻的安排方案数 mod P 的值。
Sample Input
2 4 10007
Sample Output
384 【样例说明】假设四对人生赢家分别是S-T,U-V,W-X,Y-Z ┏━━┓ ┃SUTV┃ ┃WYXZ┃ 是一种基本方案 ┗━━┛ 将四对人生赢家任意互换,再将大小写字母任意互换,产生 4!*2^4=384 种合法方案。
Data Constraint
Solution
推了推式子没推出来,实际上,Ans(n,m)=Ans(1,m)^n*(nm/2)!*2^(nm/2)
先是一列的方案数的n次方,表示n行的不同的排列的方案(没有标号的)
(nm/2)!就是将每对情侣标号排列的方案数
再乘上2^(nm/2)是每对情侣的两个人的位置互换或者说是将每对情侣的两个人再标号的方案
那么问题转换为求一行的方案数
我们可以维护 F[i][j]表示某一行已有 i 对情侣其中 j 对相邻 的方案数,则 F[n][0]即为答案,状态数 n^2,转移复杂度 O(n),时间复杂度 n^2。
F[i][j]=F[i-1][j+2]*(j+2)*(j+1) //插入的当前一对情侣不相邻,均插入到某一对情侣中的情况
+F[i-1][j+1]*(j+1)*(i+i-j-2)*2 //插入的当前一对情侣不相邻其中一个插入到某一对情侣中情况
+F[i-1][j]*(i+i-j-1)*(i+i-j-2) //插入的当前一对情侣不相邻,但未插入到某一对情侣中的情况
+F[i-1][j]*j*2 //插入的当前一对情侣相邻,但未插入到某一对情侣中的情况
+F[i-1][j-1]*(i+i-j)*2; //当 j>0 时,插入当前一对情侣到某一对情侣中的情况
对于 100%的数据 令 ans(m)=Ans(1,m),观察 ans(m)的前几项不难得到 ans(m) = (4m2 − 2m) ∗ ans(m − 1) + (2m − 2) ∗ ans(m − 2)
归纳后得到 Ans(n,m)=2^n*(nm)!*A(m)n 其中 A(0) = 1 A(1) = 0 A(n) = (2n − 1) ∗ A(n − 1) + A(n − 2) 递推求解就能很好地满足题目的要求。
Code
#include<cstdio>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define Fd(i,a,b) for(register int i=a;i>=b;--i)
#define N 10000004
using namespace std;
ll n,m,p,f[N],ans;
ll ksm(ll x,ll k){
ll sum=1;
while(k){
if(k&1) sum=(sum*x)%p;
k>>=1;x=(x*x)%p;
}
return sum;
}
I main(){
scanf("%lld%lld%lld",&n,&m,&p);
if((n*(m/=2ll))>=p){
printf("0\n");return 0;
}
f[0]=1;f[1]=0;
F(i,2,m) f[i]=((ll)(i*2ll-1ll)*f[i-1]%p+f[i-2])%p;
ans=ksm(f[m],n);
F(i,1,m*n) ans=(ans*(ll)i*2ll)%p;
printf("%lld\n",ans);
return 0;
}