2018 “百度之星”程序设计大赛 - 初赛(A) 度度熊看球赛 (DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/imzxww/article/details/81635376

http://acm.hdu.edu.cn/showproblem.php?pid=6377

思路:

dp[i][j] 表示前 i 对情侣,有 j 对坐在一起的方案数。
首先为了简便,我们把每对情侣中两个人看作是相同的两个人,最后乘上 2^n 即可。
最后要求 ans×(2N)!,也就是求出 i 对情侣坐位所有不同方案数。
然后由前 i 对递推转移到前 i+1 对 :
1、第 i+1 对在一起:
(1)第 i+1 对插入进另一对中间, dp[i+1][j] += dp[i][j] * j ;
(2)第 i+1 对不插入另一对中间,dp[i+1][j+1] += dp[i][j] * (2*i+1-j) ;
2、第 i+1 对不在一起:
(1)第 i+1 对的两个人分别插入另外两对中间,dp[i+1][j-2] += dp[i][j] * C(j,2) ;
(2)第 i+1 对的两个人只有一个人插入到另一对中间,dp[i+1][j-1] += dp[i][j] * C(j,1) ;
(3)第 i+1 对的两个人都不插入其它对里,dp[i+1][j] += dp[i][j] * C(2*i+1-j, 2) ;

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
ll dp[1010][1010];
ll qpow(ll x,ll n)        //求x^n%mod
{
    ll ret=1;
    for(; n; n>>=1)
    {
        if(n&1) ret=ret*x%mod;
        x=x*x%mod;
    }
    return ret;
}

ll C(ll a,ll b)
{
    return a*(a-1)%mod*qpow(b,mod-2)%mod;
}
void init()
{
    dp[1][1]=2;
    for(int i=1; i<1002; i++)
    {
        dp[i+1][0]=(2*dp[i][0]%mod*C(2*i+1,2)%mod+2*i*2*dp[i][1]%mod+2*dp[i][2]%mod)%mod;
        for(int j=1; j<=i+1; j++)
        {
            dp[i+1][j]=(2*dp[i][j]%mod*j%mod+2*dp[i][j-1]%mod*(2*i+1-(j-1))%mod+2*dp[i][j+2]%mod*C(j+2,2)%mod+
                        2*dp[i][j]%mod*C(2*i+1-j,2)%mod+2*dp[i][j+1]%mod*((j+1)*(2*i+1-(j+1))%mod)%mod)%mod;
        }
    }
}
int main()
{
    ll n,d;
    init();
    while(~scanf("%lld%lld",&n,&d))
    {
        ll ans=0;
        if(n==1)
        {
            printf("%lld\n",2*d%mod);
            continue;
        }
        for(int i=0;i<=n;i++) ans=(ans+dp[n][i]*qpow(d,i)%mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/imzxww/article/details/81635376