AGC022E Median Replace

题意

给出一个长度为奇数\(n\)的残缺01串,问有多少种补全方法,每次将连续三个位替换为它们的中位数后,能有一种方案使它变为1
\(n \le 3*10^5\)

思路

左边表示栈顶。
将操作简化为:将000变为0;将111变为1;删掉相邻的0110. 考虑这些操作的优先级,显然是每次有000就执行,没有就执行0110,都没有再执行 111。同类内部的顺序并不影响结果。
现在考虑用栈维护,从左往右加入串中字符,如果加入了 1,那么栈顶是 0 便可弹掉; 如果加入了 0,由于 000 优先于其他,栈顶是 1 也暂时不操作,最后再考虑 10111 操作。这样栈的形态尝试一下,就可以得出如下列举的,只有这么几种。
注意当\(1\)的个数\(\ge 2\)时,肯定是可行的,可以等价到两个的情况。
因为最后只要有两个\(1\)或者1。加起来,输出就可以了
我的状态是这样的:-, 0,1,00,01,11,001,011,0011;

#include <bits/stdc++.h>
const int N=300005,mu=1000000007;
const int tran[2][N]={{1,3,4,1,6,7,4,8,7},{2,0,5,1,2,5,4,5,7}};
int l,dp[N][10];
char s[N];
void reduce(int &x){x+=x>>31&mu;}
int main(){
	scanf("%s",s+1);
	int l=strlen(s+1);
	dp[0][0]=1;
	for (int i=1;i<=l;i++){
		for (int j=0;j<=8;j++){
			if (s[i]!='1') reduce(dp[i][tran[0][j]]+=dp[i-1][j]-mu);
			if (s[i]!='0') reduce(dp[i][tran[1][j]]+=dp[i-1][j]-mu);
		}
	}
	reduce(dp[l][5]+=dp[l][7]-mu);
	reduce(dp[l][5]+=dp[l][8]-mu);
	reduce(dp[l][5]+=dp[l][2]-mu);
	printf("%d",dp[l][5]);
} 

后记

我是来抄作业的。详见集训队作业题解。

posted @ 2019-12-06 20:06  flyfeather  阅读(404)  评论(0编辑  收藏  举报