HDU 6377 度度熊看球赛(概率dp预处理)

度度熊看球赛

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

对于每一组数据,输出一个数表示答案。

扫描二维码关注公众号,回复: 2812008 查看本文章

 

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做法。
先把一组情侣的两个人看做是相同的(最后方案数要乘上$2^N$)。

$f_{i,j}$ 表示,一共有 $i$对情侣,且正好有 $j$ 对是挨着坐的。
每次考虑把第$i+1$ 对情侣放进去:
(1)这对情侣合在一起放。
①放在某一对挨着的情侣中间(拆散他们):$F_{i+1,j}+=F_{i,j} \times j$
②放在情侣之间的空隙里:$F_{i+1,j+1}+=F_{i,j} \times (2 \times i-j+1)$
(2)这对情侣分开放。
①他们各自都拆散了一对情侣:F_{i+1,j-2}+=F_{i,j} * (j * \frac{(j-1)}{2})
②只有一个人拆散了一对情侣:F_{i+1,j-1}+=F_{i,j} \times (2 \times i-j+1) \times j
③没有情侣被拆散:
F_{i+1,j}+=F_{i,j} \times ((2 \times i-j+1) \times \frac{2 \times i-j}{2})

这样我们就能在 $O(N^2)$的时间里预处理出所有情况。
对于每一组询问,我们只要 $O(N)$扫一遍计算一下答案即可。

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/81735465
今日推荐