UOJ#748-[UNR #6]机器人表演【dp】

正题

题目链接:https://uoj.ac/problem/748


题目大意

有一个长度为\(n\)\(01\)序列,然后\(t\)次插入一个\(0\)和一个\(1\),要求\(0\)\(1\)前面,求最终能得到多少种本质不同的串。

\(1\leq n,t\leq 300\)


解题思路

我们考虑一个\(n+2\times t\)\(01\)串是否合法,而且我们最好能搞出一种记录信息最少且唯一的方法。

我们记录一个\(x\)表示当前匹配到的位置,当我们加入一个\(0\)\(1\)时,如果恰好能和下一个匹配,我们就匹配。否则如果是\(0\),我们再记录一个\(y\)表示目前有多少个未匹配的\(0\)。如果是\(1\),如果前面有未匹配的\(0\),我们就用未匹配的\(0\)和这个\(1\)匹配。

如果没有我们就一直让匹配位置\(x\)往前走,直到出现一个未匹配的\(0\),我们可以先预处理出一个\(p_i\)表示匹配位置\(i\)往前跳到出现第一个未匹配\(0\)的位置。

这种匹配方法一定是最优的,因为往前跳一到的位置一定是一个\(0\),而之后我们拿未匹配的\(0\)去匹配这个\(0\)显然不优秀。

然后我们设\(f_{i,j,k}\)表示现在填到第\(i\)个,目前匹配到位置\(j\),前面有\(k\)个未匹配的\(0\)时前面填的方案数转移即可。

时间复杂度:\(O(n^3)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=305,P=998244353;
int n,t,f[N*3][N][N],pre[N];
char s[N];
void Add(int &x,int y)
{x=(x+y>=P)?(x+y-P):(x+y);}
int main()
{
//	printf("%d\n",sizeof(f)>>20);
	scanf("%d%d",&n,&t);
	scanf("%s",s+1);pre[0]=-1;
	for(int i=1;i<=n;i++){
		int p=0;
		for(int j=i;j>=1;j--){
			if(s[j]=='1')p++;
			else p--;
			if(p==-1){pre[i]=j-1;break;}
		}
		if(p!=-1)pre[i]=-1;
	}
	f[0][0][0]=1;
	for(int i=0;i<n+2*t;i++)
		for(int j=0;j<=n;j++)
			for(int k=0;k<=t;k++){
				if(!f[i][j][k])continue;
				//zero
				if(s[j+1]=='0')Add(f[i+1][j+1][k],f[i][j][k]);
				else Add(f[i+1][j][k+1],f[i][j][k]);
				
				//one
				if(s[j+1]=='1')Add(f[i+1][j+1][k],f[i][j][k]);
				else{
					if(k)Add(f[i+1][j][k-1],f[i][j][k]);
					else if(pre[j]!=-1)Add(f[i+1][pre[j]][k],f[i][j][k]);
				}
			}
	printf("%d\n",f[n+2*t][n][0]);
	return 0;
}
posted @ 2022-08-08 11:08  QuantAsk  阅读(192)  评论(0编辑  收藏  举报