• 题解 AT3950 【[AGC022E] Median Replace】


    AtCoder

    luogu


    题意

    给你一行字符串,里面有(1,0,?),?表示既可以填(1),又可以填(0),而对于连续的三个数,可以合并,合并的结果是他们的中位数,求有多少个合法的序列满足合并的最后结果可能为1.

    输入

    [101010?11?101??010101dots 101???01 ]

    [反正就是一行字符串 ]

    分析

    我拿到这题时没有办法,所以纯粹是听了老师讲了之后才懂的。老师说这类题(相邻的数合并)大多数都是用的一个栈模型来解决,为什么可以用栈模型,因为可以贪心

    注意:我们这里的栈是0一边,1一边

    栈.png

    所以我们可以看这三个例子:

    1. $dots 000 dots $

    对于这连续的三个零,我们应不应该合并,因为我们要求的最后是一,而在这里是三个零互相抵消,然后变为一个零,我们肯定是稳赚不赔的!

    1. $dots 01dots $
      这里我们可以看到,我们之后的数加入为1,那合并就为1,反之亦然。所以这个可以直接在栈中“抵消”

    2. (1111dots)(这是在栈中)

    我们通过前两个规则都可以知道,栈中的0最多有两个,那两个0用几个1就可以使中位数为一了呢,当然是三个就可以了,所以这个时候放入一也可以直接抵消


    代码

    通过我们前三个规则就可以打出代码了:

    #include<cstdio>
    #include<iostream>
    #define re register int
    #define Starseven main
    #define ll long long
    using namespace std;
    const int N=3e5+20;
    const ll mod=1e9+7;
    int num[N],len;
    ll dp[N][4][4];
    
    int Starseven(void){
    	while(1){
    		len++;
    		char ch=getchar();
    		if(ch=='
    ') break;
    		while(ch!='0'&&ch!='1'&&ch!='?'){
    			ch=getchar();
    		}
    		if(ch=='1') num[len]=1;
    		else if(ch=='0') num[len]=2;
    		else num[len]==0; 
    	}
    	len--;
    	dp[0][0][0]=1;
    	for(re i=1;i<=len;i++){
    		if(num[i]){
    			if(num[i]==1){
    				dp[i][1][0]=(dp[i][1][0]+dp[i-1][0][0]+dp[i-1][1][1])%mod;
    				dp[i][2][0]=(dp[i][2][0]+dp[i-1][1][0]+dp[i-1][2][1])%mod;
    				dp[i][3][0]=(dp[i][3][0]+dp[i-1][2][0]+dp[i-1][3][1]+dp[i-1][3][0])%mod;
    				dp[i][0][0]=(dp[i][0][0]+dp[i-1][0][1])%mod;
    				for(re j=0;j<=3;j++) dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][2])%mod;
    			}
    			else{
    				for(re j=0;j<=3;j++) dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][0]+dp[i-1][j][2])%mod;
    				for(re j=0;j<=3;j++) dp[i][j][2]=(dp[i][j][2]+dp[i-1][j][1])%mod;
    			}
    		}
    		else{
    			dp[i][1][0]=(dp[i][1][0]+dp[i-1][0][0]+dp[i-1][1][1])%mod;
    			dp[i][2][0]=(dp[i][2][0]+dp[i-1][1][0]+dp[i-1][2][1])%mod;
    			dp[i][3][0]=(dp[i][3][0]+dp[i-1][2][0]+dp[i-1][3][1]+dp[i-1][3][0])%mod;
    			dp[i][0][0]=(dp[i][0][0]+dp[i-1][0][1])%mod;
    			for(re j=0;j<=3;j++) dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][2])%mod;
    			
    			for(re j=0;j<=3;j++) dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][0]+dp[i-1][j][2])%mod;
    			for(re j=0;j<=3;j++) dp[i][j][2]=(dp[i][j][2]+dp[i-1][j][1])%mod;
    		}
    	}
    	ll ans=0;
    	for(re i=0;i<=3;i++) ans=(ans+dp[len][i][0])%mod;
    	ans=(ans+dp[len][2][1]+dp[len][3][1]+dp[len][3][2])%mod;
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    UNION ALL
    jquery.validate的使用
    通过匹配绑定select option的文本值 模糊匹配
    .net 时间操作[摘抄]
    判断Table表中是否含有某一列
    将数组,表的某一列转换为string字符串的方法
    选出某一列不重复,某一列作为选择条件,其他列正常输出(摘抄)
    SQLite 解决:Could not load file or assembly 'System.Data.SQLite ... 试图加载格式不正确的程序(转)
    金山毒霸占用80端口
    DropDownList 绑定数据后 插入一条不属于表中的数据
  • 原文地址:https://www.cnblogs.com/starseven/p/13110345.html
Copyright © 2020-2023  润新知