2018 百度之星 初赛A 1004 度度熊看球赛 【DP】

【题意】:

链接:度度熊看球赛

        有一排2*N个椅子,现在有N对情侣来看球赛,每个人随机坐在一个椅子上。再给你一个D,如果有k对情侣相邻而坐,就会产生D^{k}的喧闹值。问你期望的喧闹值,为了避免出现浮点数,答案乘以(2*N)!,并且对998244353取模。

【题解】:

官方题解很巧妙,讲的非常好。

官方题解:


我这里就再赘述一下:

先假设,永远是女生坐在男生右边。(每对情侣可以选择男女交换位置或者不换,有2^{N}种情况,乘上后就是总的方案数)

dp[ i ][ j ] 表示有i对情侣,j对坐在一起。

预处理:dp[1][0]=0, dp[1][1]=1。// 可以简单得出

for(int i=2;i<=1000;i++){//有i对情侣
        for(int j=0;j<=i;j++){//i对中有j对坐在一起
            dp[i][j]=(dp[i][j]+dp[i-1][j]*(j))%mod;//(1).1
            dp[i][j]=(dp[i][j]+dp[i-1][j]*(((2*(i-1)-j+1)*(2*(i-1)-j)/2)%mod)%mod)%mod;//(2).3
            if(j+1<=i-1) dp[i][j]=(dp[i][j]+dp[i-1][j+1]*(j+1)%mod*(2*(i-1)-j)%mod)%mod;//(2).1
            if(j+2<=i-1) dp[i][j]=(dp[i][j]+dp[i-1][j+2]*(((j+2)*(j+1)/2)%mod)%mod)%mod;//(2).2
            if(j>0) dp[i][j]=(dp[i][j]+dp[i-1][j-1]*(2*i-j)%mod)%mod;//(1).2
        }
    }

(1) 如果这对情侣坐在一起:

         1.   这对情侣坐在某对情侣之间,拆散了她们,那么坐在一起的情侣对数不变,dp[ i ][ j ]+=dp[ i-1 ][ j ] * j。

      2.  这对情侣没有拆散别的情侣,那么就是插空坐,情侣对数增加1。每对情侣之间的空不能插,这样一共有 2*(i-1)+1-(j -1)个空可以插,dp [ i ] [ j ] += dp [ i -1 ] [ j -1 ] * ( 2* i - j )。

(2)如果这对情侣分开坐:

         1.  这对情侣拆散其他一对情侣,那么坐在一起的情侣对数减少1,这里默认是男生去拆散别人(别问我为什么,当成女生去拆散别人也可以),这样男生会插坐在一起的情侣的空,女生会插其他空。dp[ i ][ j ] += dp[ i-1 ][ j+1 ]*( j+1)*( 2*( i-1 ) - j )

         2. 这对情侣拆散其他两对情侣,那么坐在一起的情侣对数减少2,男生和女生都去插坐在一起的情侣的空,这里会重复计算,要除以2。dp[ i ][ j ] += dp[ i-1 ][ j+2 ]*( j+2 )*( j+1 ) / 2。

         3.  这对情侣不拆散别人,那么各自插不是情侣之间的空坐。 dp[ i ][ j ] +=dp[ i-1 ][ j ]* (2*(i-1)-j+1)* ( 2*( i-1 ) -j ) /2。

【代码】:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 998244353;
ll dp[1005][1005];
ll d[1005][1005];
int main(void)
{
    int N,D;
    dp[1][1]=1;
    for(int i=2;i<=1000;i++){
        for(int j=0;j<=i;j++){
            dp[i][j]=(dp[i][j]+dp[i-1][j]*(j))%mod;
            dp[i][j]=(dp[i][j]+dp[i-1][j]*(((2*(i-1)-j+1)*(2*(i-1)-j)/2)%mod)%mod)%mod;
            if(j+1<=i-1) dp[i][j]=(dp[i][j]+dp[i-1][j+1]*(j+1)%mod*(2*(i-1)-j)%mod)%mod;
            if(j+2<=i-1) dp[i][j]=(dp[i][j]+dp[i-1][j+2]*(((j+2)*(j+1)/2)%mod)%mod)%mod;
            if(j>0) dp[i][j]=(dp[i][j]+dp[i-1][j-1]*(2*i-j)%mod)%mod;
        }
    }
    for(int i=1;i<=1000;i++){
        d[i][0]=1;
        for(int j=1;j<=1000;j++){
            d[i][j]=d[i][j-1]*i%mod;
        }
    }


    while(~scanf("%d%d",&N,&D)){
        ll ans=0;
        for(int i=0;i<=N;i++){
            //printf("%lld\n",dp[N][i]);
            ans=(ans+dp[N][i]*d[D][i]%mod*d[2][N]%mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/gymgym1212/article/details/81610701