AGC022E Median Replace

北城以北 提交于 2019-12-06 20:18:28

题意

给出一个长度为奇数\(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]);
} 

后记

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!