度度熊看球赛
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 289 Accepted Submission(s): 128
Problem Description
世界杯正如火如荼地开展!度度熊来到了一家酒吧。
有 N 对情侣相约一起看世界杯,荧幕前正好有 2×N 个横排的位置。
所有人都会随机坐在某个位置上。
当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看。
一般地,对于一个就座方案,如果正好有 K 对情侣正好是挨着坐的,就会产生 DK 的喧闹值。
度度熊想知道随机就座方案的期望喧闹值。
为了避免输出实数,设答案为 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
题意:
有n对情侣,2n个位置,当有k对情侣坐在一起的时候,就会产生D^k的喧闹值
问你喧闹值的期望*(2n)! MOD 998244353的值
解析:
一开始想了dp,但是我用dp[i][j]标记前i位,已经j对情侣坐在一起,但这个有点问题,
因为不知道在前i位里面有多少情侣是不坐在一起的。所以看了题解...他把i换成了前面已经坐i对情侣了
官方题解
此题有两种做法,这里介绍一种比较精妙的DP做法。
先把一组情侣的两个人看做是相同的(最后方案数要乘上)。
设 表示,一共有 对情侣,且正好有 对是挨着坐的。
每次考虑把第 对情侣放进去:
(1)这对情侣合在一起放。
①放在某一对挨着的情侣中间(拆散他们):
②放在情侣之间的空隙里:
(2)这对情侣分开放。
①他们各自都拆散了一对情侣:
②只有一个人拆散了一对情侣:
③没有情侣被拆散:
这样我们就能在 的时间里预处理出所有情况。
对于每一组询问,我们只要 扫一遍计算一下答案即可。
#include <cstdio>
#include <cstring>
typedef long long ll;
const ll MOD = 998244353;
const int MAXN = 1E3+10;
int dp[MAXN][MAXN];
int two[MAXN];
int main()
{
int n,m;
two[0]=1;
for(int i=1;i<MAXN;i++)
{
two[i]=1ll*two[i-1]*2%MOD;
}
dp[0][0]=1;
for(int i=0;i<1000;i++)
{
for(int j=0;j<=i;j++)
{
ll tmp=2*i-j+1;
dp[i+1][j]=(dp[i+1][j]+1ll*dp[i][j]*j%MOD)%MOD;
dp[i+1][j+1]=(dp[i+1][j+1]+1ll*dp[i][j]*(tmp)%MOD)%MOD;
if(j-2>=0)
dp[i+1][j-2]=(dp[i+1][j-2]+1ll*dp[i][j]*((j*(j-1)/2)%MOD)%MOD)%MOD;
if(j-1>=0)
dp[i+1][j-1]=(dp[i+1][j-1]+1ll*dp[i][j]*j%MOD*(tmp)%MOD)%MOD;
dp[i+1][j]=(dp[i+1][j]+1ll*dp[i][j]*((tmp*(tmp-1)/2)%MOD)%MOD)%MOD;
}
}
while(~scanf("%d%d",&n,&m))
{
int ans=0;
int temp=1;
for(int i=0;i<=n;i++)
{
ans=(ans+1ll*dp[n][i]%MOD*temp%MOD*two[n]%MOD)%MOD;
temp=1ll*temp*m%MOD;
}
printf("%d\n",ans);
}
return 0;
}