HDU-3677 度度熊看球赛(dp)

度度熊看球赛

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 346    Accepted Submission(s): 153

Problem Description

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

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

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

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

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

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

为了避免输出实数,设答案为 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

Source

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

 

中文题意很好懂,就不解释了

思路:dp[i][j]表示有i对情侣,有j对坐在一块。
讨论第i+1对情侣不同的位置的方案数。
首先第i+1这两个人,可以将现有的j对中的两对拆开,j对选2对有顺序,dp[i+1][j-2]+=dp[i][j] * j * (j-1);
第i+1这两个人,可以将现有的j对中的一对拆开,并且第i+1对不在一块,j对选1对,另一个人插空  站(有2*i-j+1个空隙),
dp[i+1][j-1]+=dp[i][j] * j * 2 * (2* i -j+1);
加入第i+1对人,还是有j对在一块,一种情况是2个人都插空 站,(2*i-j+1)个空隙选两个位置有顺序,另一种情况是第i+1对人本身就在一块,并且他们还拆了一对,这样还是j对,所以当前 j对选一对插中间,并且第i+1对这两个人有01,10两种情况;
dp[i+1][j]+=dp[i][j]*((2*i-j+1)*(2*i-j)+2*j);
加入第i+1对人,第i+1对人本身就在一块,并且他们没有拆开j对情侣中的任何一个,有(2*i-j+1)个空隙,并且第i+1对这两个人有01,10两种情况,dp[i+1][j+1]+=dp[i][j]*2*(2*i-j+1);

预处理dp,对于查询for一遍n对人,有i对情侣在一起即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=998244353;
using namespace std;
const LL N =1e3+100;
LL dp[N][N];
LL poww(LL a,LL b)
{
    LL ans=1;
    while(b)
    {
        if(b&1) (ans*=a)%=mod;
        (a*=a)%=mod;
        b/=2;
    }
    return ans;
}
int main()
{
    mem(dp,0);
    dp[0][0]=1;
    for(LL i=0;i<=1000;i++)
    {
        for(LL j=0;j<=i;j++)
        {
            if(j>=2) (dp[i+1][j-2]+=dp[i][j]*j*(j-1))%=mod;
            if(j>=1) (dp[i+1][j-1]+=dp[i][j]*j*2*(2*i-j+1))%=mod;
            (dp[i+1][j]+=dp[i][j]*((2*i-j+1)*(2*i-j)+2*j))%=mod;
            (dp[i+1][j+1]+=dp[i][j]*2*(2*i-j+1))%=mod;
        }
    }
    LL n,k;
    while(~scanf("%lld%lld",&n,&k))
    {
        LL ans=0;
        for(LL i=0;i<=n;i++)
            (ans+=poww(k,i)*dp[n][i])%=mod;
        printf("%lld\n",ans);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值