2021国庆CSP/NOIP冲刺营Contest02 B.排队

【题意】

n 名男生和 n 名女生要排成一列。女生用 0 表示,男生用 1 表示。当前队列中已经站好了 m 位同学,现在剩下的 nm 个同学要补到队列当中。这些同学可以站到队列中的任意位置,但是队列中原本的 m 个同学的相对位置不能发生改变。

此外,还有一个规定:对于每一个同学,他右边男生的数量都不能小于女生的数量。

我们定义两个方案是不同的,当且仅当存在一个位置,使得在两个方案中这个位置上的同学性别不同。(也就是相同性别的同学不区分)

求所有人站好后有多少种列队方案。答案对 998244353 取模。

【分析】

设f[i][j][k]表示现插入了i个,匹配到j对应的位置,剩余k个女生在左侧等待匹配的方案数

那么直接转移即可,注意一种填法可能对应多个匹配原串的方式,我们让左括号尽可能地先匹配来避免算重

【代码】

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
int n,m;
ll f[405][405][405];
int init[405];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d",&init[i]);
    f[0][0][0]=1;
    for(int i=0;i<=2*n-m;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=n;k++)
            {
                //填 0 能匹配尽量匹配
                if(j<m && init[j+1]==0) f[i][j+1][k+1]=(f[i][j+1][k+1]+f[i][j][k])%mod;
                else f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k])%mod;
                // 填 1 能匹配尽量匹配
                if(!k) continue;
                if(j<m && init[j+1]==1) f[i][j+1][k-1]=(f[i][j+1][k-1]+f[i][j][k])%mod;
                else f[i+1][j][k-1]=(f[i+1][j][k-1]+f[i][j][k])%mod;
            }
    printf("%d",f[2*n-m][m][0]);
    return 0;
}

 

posted @ 2021-10-31 20:10  andyc_03  阅读(38)  评论(0编辑  收藏  举报