2021国庆CSP/NOIP冲刺营Contest02 B.排队
【题意】
有 n 名男生和 n 名女生要排成一列。女生用 0 表示,男生用 1 表示。当前队列中已经站好了 m 位同学,现在剩下的 n−m 个同学要补到队列当中。这些同学可以站到队列中的任意位置,但是队列中原本的 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; }