度度熊看球赛
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 346 Accepted Submission(s): 153
Problem Description
世界杯正如火如荼地开展!度度熊来到了一家酒吧。
有 N 对情侣相约一起看世界杯,荧幕前正好有 2×N 个横排的位置。
所有人都会随机坐在某个位置上。
当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看。
一般地,对于一个就座方案,如果正好有 K 对情侣正好是挨着坐的,就会产生 D^k 的喧闹值。
度度熊想知道随机就座方案的期望喧闹值。
为了避免输出实数,设答案为 ans,请输出 ans×(2N)! mod P 的值。其中 P=998244353
Input
有多组数据(不超过 1000 组),读到EOF结束。
对于每一组数据,读入两个数 N 和 D 。
1≤N,D≤1000
Output
对于每一组数据,输出一个数表示答案。
Sample Input
1 10
2 3
Sample Output
20
104
Source
中文题意很好懂,就不解释了
思路:dp[i][j]表示有i对情侣,有j对坐在一块。
讨论第i+1对情侣不同的位置的方案数。
首先第i+1这两个人,可以将现有的j对中的两对拆开,j对选2对有顺序,dp[i+1][j-2]+=dp[i][j] * j * (j-1);
第i+1这两个人,可以将现有的j对中的一对拆开,并且第i+1对不在一块,j对选1对,另一个人插空 站(有2*i-j+1个空隙),
dp[i+1][j-1]+=dp[i][j] * j * 2 * (2* i -j+1);
加入第i+1对人,还是有j对在一块,一种情况是2个人都插空 站,(2*i-j+1)个空隙选两个位置有顺序,另一种情况是第i+1对人本身就在一块,并且他们还拆了一对,这样还是j对,所以当前 j对选一对插中间,并且第i+1对这两个人有01,10两种情况;
dp[i+1][j]+=dp[i][j]*((2*i-j+1)*(2*i-j)+2*j);
加入第i+1对人,第i+1对人本身就在一块,并且他们没有拆开j对情侣中的任何一个,有(2*i-j+1)个空隙,并且第i+1对这两个人有01,10两种情况,dp[i+1][j+1]+=dp[i][j]*2*(2*i-j+1);
预处理dp,对于查询for一遍n对人,有i对情侣在一起即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=998244353;
using namespace std;
const LL N =1e3+100;
LL dp[N][N];
LL poww(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) (ans*=a)%=mod;
(a*=a)%=mod;
b/=2;
}
return ans;
}
int main()
{
mem(dp,0);
dp[0][0]=1;
for(LL i=0;i<=1000;i++)
{
for(LL j=0;j<=i;j++)
{
if(j>=2) (dp[i+1][j-2]+=dp[i][j]*j*(j-1))%=mod;
if(j>=1) (dp[i+1][j-1]+=dp[i][j]*j*2*(2*i-j+1))%=mod;
(dp[i+1][j]+=dp[i][j]*((2*i-j+1)*(2*i-j)+2*j))%=mod;
(dp[i+1][j+1]+=dp[i][j]*2*(2*i-j+1))%=mod;
}
}
LL n,k;
while(~scanf("%lld%lld",&n,&k))
{
LL ans=0;
for(LL i=0;i<=n;i++)
(ans+=poww(k,i)*dp[n][i])%=mod;
printf("%lld\n",ans);
}
}