• AGC022E Median Replace


    Median Replace

    有个奇数长度的01串(s),其中有若干位置是?。

    每次可将(3)个连续的字符替换成这三个数的中位数。

    求有多少方案将?替换成0/1使得进行(frac{N-1}{2})次操作后的字符串是1?

    (1leq |S|leq 300000)

    题解

    仓鼠《动态规划选讲》。

    很多这样的题,套路就是先考虑一个判定的过程,然后把过程写到DP里面去就可以了。所有我们先考虑判定的过程。

    维护一个栈,这个栈满足存在一个分界点,前面全是1后面全是0。这里前面后面指的是,把栈从栈底向栈顶写下来。然后从左往右扫。

    如果当前是0,就把0压入到栈里面去。如果有连续的三个0,可以把这(3)个0消掉(2)个变成(1)个0。

    如果当前是1,当栈顶是一个0的时候显然可以相互抵消(因为再找一个数取中位数,取决于再找的数),否则直接压入栈。

    一个显然的事情是,栈里面0的个数不超过(2)。同时,当栈里面1的个数达到(2)时,那么最终一定可以让字符串变成1。因此,当1的个数超过(2)时,可以看成就是(2)

    所以栈的种类数只有(3 × 3 = 9)种。

    最终可以变成1的条件,就是最后的栈里面1个数不少于0个数。

    直接把当前栈长成什么样记下来,从左往右DP即可。

    时间复杂度是(O(N))

    CO int N=3e5+10;
    char str[N];
    int F[N][3][3];
    
    int main(){
    	scanf("%s",str+1);
    	int n=strlen(str+1);
    	F[0][0][0]=1;
    	for(int i=1;i<=n;++i){
    		for(int j=0;j<=2;++j)for(int k=0;k<=2;++k){
    			if(str[i]!='0'){
    				if(k) chkadd(F[i][j][k-1],F[i-1][j][k]);
    				else chkadd(F[i][min(j+1,2)][k],F[i-1][j][k]);
    			}
    			if(str[i]!='1'){
    				if(k==2) chkadd(F[i][j][1],F[i-1][j][k]);
    				else chkadd(F[i][j][k+1],F[i-1][j][k]);
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<=2;++i)for(int j=0;j<=i;++j)
    		chkadd(ans,F[n][i][j]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    页面性能:如何系统地优化页面?
    为什么CSS动画比JavaScript高效?
    Code Review
    浏览器中的页面之CSS是如何影响到渲染流程的
    async / await
    手撸Promise
    Promise
    宏任务和微任务
    有点恶心,随手写点儿
    关于判断用户输入的是不是int类型,这次没有正则表达式
  • 原文地址:https://www.cnblogs.com/autoint/p/12731582.html
Copyright © 2020-2023  润新知