题解 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;
}
本博客作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,转载时请注明出处,谢谢支持!