zoukankan      html  css  js  c++  java
  • 题解 CF296B 【Yaroslav and Two Strings】

    题目

    传送门

    题目大意

    如果两个只包含数字且长度为 (n) 的字符串 (s)(w) 存在两个数字 (1≤i,j≤n),使得 (s_i<w_i,s_j>w_j) ,则称 (s)(w) 是不可比的。现在给定两个包含数字和问号且长度为 (n) 的字符串,问有多少种方案使得将所有问号替换成 (0)(9) 的数字后两个字符串是不可比的?

    思路

    分析

    DP 题, 我们注意到,只要有一对这样的数就可以满足条件,而等于是不属于判断情况的,因此我们要单独记一个状态。

    状态

    f[i][k]: 当在第 $i$ 位时,第 $k$ 种情况的方案数。
    以下: j < i
    k = 0 : 前面只出现了 s[j] < w[j] 的情况,并没有 s[j] > w[j] ,即 s[j] <= w[j]
    k = 1 : 前面 s[j] < w[j] , s[j] > w[j]
    k = 2 : 前面只出现了 s[j] > w[j] 的情况,并没有 s[j] < w[j] ,即 s[j] >= w[j]
    k = 3 : 前面只有 s[j] == w[j] 情况
    

    转移

    我们要对每一位考虑该位上填每个数字的情况。

    对于已经确定数字的位,我们要只要对该数字讨论。

    如果有'?',我们要枚举 1~9 进行转移。

    感觉有点像数位DP?

    初始状态

    f[0][3] = 1
    

    代码

    按照各种状态进行转移即可,代码量有点大。

    当然,也有一种代码量小的解法,可以预先算出每种情况转移,就不必枚举。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <string>
    
    #define ll long long
    using namespace std;
    
    const int MAXN = 1e5+10;
    const ll mod = 1e9+7;
    
    int n;
    ll f[MAXN][4];
    char s[MAXN],w[MAXN];
    
    int main (){
    	scanf("%d",&n);
    	scanf("%s",s+1);
    	scanf("%s",w+1);
    	f[0][0] = f[0][1] =f[0][2] = 0;
    	f[0][3] = 1;
    	for(int i = 1;i <= n;i++){
    		if(s[i] != '?' &&w[i] != '?'){
    			if(s[i] > w[i]) {
    				f[i][0] = 0;
    				f[i][1] = f[i-1][0] + f[i-1][1];
    				f[i][2] = f[i-1][2] + f[i-1][3];
    				f[i][3] = 0;
    			} else if(s[i] == w[i]){
    				f[i][0] = f[i-1][0];
    				f[i][1] = f[i-1][1];
    				f[i][2] = f[i-1][2];
    				f[i][3] = f[i-1][3];
    			} else{
    				f[i][0] = f[i-1][0] + f[i-1][3];
    				f[i][1] = f[i-1][2] + f[i-1][1];
    				f[i][2] = 0;
    				f[i][3] = 0;
    			}
    		} else if(s[i] == '?' && w[i] != '?'){
    			for(int j = '0';j < w[i] ;j++){
    				f[i][0] += f[i-1][0] + f[i-1][3];
    				f[i][1] += f[i-1][1] + f[i-1][2];
    				f[i][2] += 0;
    			}
    			f[i][0] += f[i-1][0];
    			f[i][1] += f[i-1][1];
    			f[i][2] += f[i-1][2];
    			f[i][3] += f[i-1][3];
    			for(int j = w[i] + 1;j <= '9';j++){
    				f[i][1] += f[i-1][0] + f[i-1][1];
    				f[i][2] += f[i-1][2] + f[i-1][3];
    			}
    		} else if(s[i] != '?' && w[i] == '?'){
    			
    			for(int j = '0' ;j < s[i] ;j++){
    				f[i][1] += f[i-1][0] + f[i-1][1];
    				f[i][2] += f[i-1][2] + f[i-1][3];
    			}
    			f[i][0] += f[i-1][0];
    			f[i][1] += f[i-1][1];
    			f[i][2] += f[i-1][2];
    			f[i][3] += f[i-1][3];
    			for(int j = s[i] +1;j <= '9' ;j++){
    				f[i][0] += f[i-1][0] + f[i-1][3];
    				f[i][1] += f[i-1][1] + f[i-1][2];
    			}
    		} else{
    			for(int j = 0;j < 10;j++){
    				for(int k = 0;k < 10;k++){
    					if(j<k){
    						f[i][0] += (f[i-1][0] + f[i-1][3])%mod;
    						f[i][1] += (f[i-1][1] + f[i-1][2])%mod;
    					} else if(j == k){
    						f[i][0] += f[i-1][0];
    						f[i][1] += f[i-1][1];
    						f[i][2] += f[i-1][2];
    						f[i][3] += f[i-1][3];
    					} else{
    						f[i][1] += (f[i-1][0] + f[i-1][1])%mod;
    						f[i][2] += (f[i-1][2] + f[i-1][3])%mod;
    					}
    					f[i][0] %= mod;
    					f[i][1] %= mod;
    					f[i][2] %= mod;
    				}
    			}
    		}
    		f[i][0] %= mod;
    		f[i][1] %= mod;
    		f[i][2] %= mod;
    	}
    	printf("%d",f[n][1] % mod);
    	return 0;
    }
    
  • 相关阅读:
    联赛模拟测试19
    联考Day5
    联赛模拟测试18(A.施工未补)
    题解 CF960G 【Bandit Blues】
    题解 P5518 【[MtOI2019]幽灵乐团 / 莫比乌斯反演基础练习题】
    概率与数学期望笔记
    题解 P3704 【[SDOI2017]数字表格】
    主定理
    【题解】Hikari与组合数
    【题解】P2303 [SDOI2012] Longge 的问题
  • 原文地址:https://www.cnblogs.com/werner-yin/p/13306330.html
Copyright © 2011-2022 走看看