Problem Description
世界杯正如火如荼地开展!度度熊来到了一家酒吧。
有 NNN 对情侣相约一起看世界杯,荧幕前正好有 2×N2 \times N2×N 个横排的位置。
所有人都会随机坐在某个位置上。
当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看。
一般地,对于一个就座方案,如果正好有 KKK 对情侣正好是挨着坐的,就会产生 DKD^KDK 的喧闹值。
度度熊想知道随机就座方案的期望喧闹值。
为了避免输出实数,设答案为 ansansans,请输出 ans×(2N)!ans \times (2N)!ans×(2N)! modmodmod PPP 的值。其中 P=998244353P=998244353P=998244353
Input
有多组数据(不超过 100010001000 组),读到EOF结束。
对于每一组数据,读入两个数 NNN 和 DDD 。
扫描二维码关注公众号,回复:
2743249 查看本文章
1≤N,D≤10001 \leq N,D \leq 10001≤N,D≤1000
Output
对于每一组数据,输出一个数表示答案。
Sample Input
Copy
1 10
2 3
Sample Output
Copy
20
104
额,看了题解写的。。。。。。。
因为这个dp仅仅是枚举,并没有求最优状态,所以正向是完全没问题的,那这样是不是说最优只能逆向思维呢,额,姑且看成是这样吧。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1010
#define p 998244353
long long dp[MAXN][MAXN]; //dp[i][j]表示i对人有j对情侣坐在一起
long long pow_mod(long long a,long long x)
{
long long ans=1; //p是取模的数
long long base=a%p;
while(x>0)
{
if((x&1)==1)
ans=(ans*base)%p; //if里的条件也可以写成x&1
base=base*base%p;
x=x>>1;
}
return ans;
}
long long N,D;
void Init()
{
memset(dp,0,sizeof(dp));
int i,j;
dp[1][0]=0;
dp[1][1]=1; //先把一组情侣的两个人看做是相同的(最后方案数要乘上2^i)
for(i=1;i<=1000;i++) //i<MAXN;就会很耗时间。
for(j=0;j<=i;j++)
{
//每次考虑把第 i+1 对情侣放进去
//也就是后一状态。
//这对情侣合在一起放。
// 1.放在某一对挨着的情侣中间(拆散他们):
dp[i+1][j]+=dp[i][j]*j%p; //因为dp加起来还是很大的
dp[i+1][j]%=p;
//2.放在情侣之间的空隙里:
dp[i+1][j+1]+=dp[i][j]*(2*i-j+1)%p; //2*i+1个缝隙减去j个情侣之间的缝隙。
dp[i+1][j+1]%=p;
//这对情侣分开放
//他们各自都拆散了一对情侣:
if(j>=2)
{
dp[i+1][j-2]+=dp[i][j]*j*(j-1)/2%p; //C(j,2)
dp[i+1][j-2]%=p;
}
//只有一个人拆散了一对情侣:
if(j>=1)
{
dp[i+1][j-1]+=dp[i][j]*(2*i-j+1)*j%p; //(2*i+1-j)个其他空隙,j个那个空隙,你懂的,额
dp[i+1][j-1]%=p;
}
//没有情侣被拆散
dp[i+1][j]+=dp[i][j]*(2*i-j+1)*(2*i-j)/2%p; //C(....,2)
dp[i+1][j]%=p;
}
}
int main()
{
//顺推的话,自然就是找之后的状态,这里是对数加一,也就是说是加第一个for的参数
//这应该是顺推的DP,因为逆推太难了,本来逆推的话,就是找前一状态,前一状态好找的话,就省很多时间,
//其实不妨假设用逆推,dp[i][j]表示i对人有j对人坐在一起
//排列组合用DP正推。
Init();
while(scanf("%lld%lld",&N,&D)!=EOF)
{
long long k;
long long ans=0;
for(k=0;k<=N;k++)
{
long long temp=pow_mod(D,k);
temp*=pow_mod(2,N); //这两个一乘就超int了
temp%=p;
ans+=dp[N][k]*temp%p; //反正加取模,再取模就是连环加模
ans%=p;
}
printf("%lld\n",ans);
}
return 0;
}