AGC022E Median Replace
题意
给出一个长度为奇数\(n\)的残缺01
串,问有多少种补全方法,每次将连续三个位替换为它们的中位数后,能有一种方案使它变为1
。
\(n \le 3*10^5\)
思路
左边表示栈顶。
将操作简化为:将000
变为0
;将111
变为1
;删掉相邻的01
或10
. 考虑这些操作的优先级,显然是每次有000
就执行,没有就执行01
或10
,都没有再执行 111
。同类内部的顺序并不影响结果。
现在考虑用栈维护,从左往右加入串中字符,如果加入了 1
,那么栈顶是 0
便可弹掉; 如果加入了 0
,由于 000
优先于其他,栈顶是 1
也暂时不操作,最后再考虑 10
和 111
操作。这样栈的形态尝试一下,就可以得出如下列举的,只有这么几种。
注意当\(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μ}
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]);
}
后记
我是来抄作业的。详见集训队作业题解。
* 生而自由 爱而无畏 *
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步