HDU-3677:度度熊看球赛(DP)

度度熊看球赛
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)

Problem Description
世界杯正如火如荼地开展!度度熊来到了一家酒吧。

有 N 对情侣相约一起看世界杯,荧幕前正好有 2 × N 个横排的位置。

所有人都会随机坐在某个位置上。

当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看。

一般地,对于一个就座方案,如果正好有 K 对情侣正好是挨着坐的,就会产生 D K 的喧闹值。

度度熊想知道随机就座方案的期望喧闹值。

为了避免输出实数,设答案为 a n s ,请输出 a n s × ( 2 N ) ! m o d P 的值。其中 P = 998244353

Input
有多组数据(不超过 1000 组),读到EOF结束。

对于每一组数据,读入两个数 N 和 D 。

1 N , D 1000

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

Sample Input
1 10
2 3

Sample Output
20
104

思路: d [ i ] [ j ] 表示 i 对情侣其中有 j 对是挨着坐的方案数。
每次考虑把第 i + 1 对情侣放进去:
(1)这对情侣合在一起放。
①放在某一对挨着的情侣中间(拆散他们).
②放在情侣之间的空隙里.
(2)这对情侣分开放。
①他们各自都拆散了一对情侣。(即拆开分别放在一对情侣中间)
②只有一个人拆散了一对情侣。(一个放在一对情侣中间,另一个放在情侣间的空隙)
③没有情侣被拆散。(分别放在情侣间的空隙里)

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3+10;
const int MOD=998244353;
const int INF=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll POW(ll x,ll n)
{
    ll res=1;
    while(n)
    {
        if(n&1)res=res*x%MOD;
        x=x*x%MOD;
        n/=2;
    }
    return res;
}
ll C(ll n,ll m){return n*(n-1)/2;}
ll d[MAX][MAX];
int main()
{
    d[0][0]=1;
    for(int i=1;i<=1000;i++)
    for(int j=0;j<=i;j++)
    {
        if(j<i)(d[i][j+1]+=2*d[i-1][j]*(2*(i-1)+1-j)%MOD)%=MOD;
        (d[i][j]+=2*d[i-1][j]*j%MOD)%=MOD;
        (d[i][j]+=2*d[i-1][j]*C(2*(i-1)+1-j,2)%MOD)%=MOD;
        (d[i][j]+=2*d[i-1][j+1]*(2*(i-1)+1-(j+1))*(j+1)%MOD)%=MOD;
        (d[i][j]+=2*d[i-1][j+2]*C(j+2,2)%MOD)%=MOD;
    }
    int n,D;
    while(scanf("%d%d",&n,&D)!=EOF)
    {
        int ans=0;
        for(int i=0;i<=n;i++)(ans+=POW(D,i)*d[n][i]%MOD)%=MOD;
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81698454