文章目录
- 题目描述
- 输入格式
- 输出格式
- 样例
- 样例输入 #1
- 样例输出 #1
- 样例输入 #2
- 样例输出 #2
- 样例输入 #3
- 样例输出 #3
- 提示
- 提交链接
- 解析
- 参考代码
题目描述
给您两个二进制字符串 a a a 和 b b b 。二进制字符串是由字符 0 0 0 和 1 1 1 组成的字符串。
您的任务是确定最大可能的数字 k k k,使得长度为 k k k 的字符串 a a a 的前缀是字符串 b b b 的子序列。
如果 a a a 可以从 b b b 中删除几个(可能是零个或全部)元素,那么序列 a a a 就是序列 b b b 的子序列。
输入格式
第一行包含两个整数 n n n 和 m ( 1 ≤ n , m ≤ 2 ∗ 1 0 5 ) m(1 \leq n,m \leq 2 * 10^5) m(1≤n,m≤2∗105) - 分别是字符串 a a a 的长度和字符串 b b b 的长度。
第二行包含长度为 n n n 的二进制字符串 a a a 。
第三行包含长度为 m m m 的二进制字符串 b b b。
输出格式
输出一个数字 - 最大值 k k k ,使得 a a a 的前 k k k 个字符构成 b b b 的子序列。
样例
样例输入 #1
5 4
10011
1110
样例输出 #1
2
样例输入 #2
3 5
100
11010
样例输出 #2
3
样例输入 #3
3 1
100
0
样例输出 #3
0
提示
样例解释 1 1 1:
字符串 10 10 10 是 1110 1110 1110 的子序列,但字符串 100 100 100 不是。因此答案是 2 2 2 。
样例解释 2 2 2:
a = 100 a=100 a=100, b = 11010 b=11010 b=11010,整个字符串 a a a 是字符串 b b b 的子序列,所以答案为 3 3 3。
样例解释 3 3 3:
字符串 b b b 不包含 1 1 1,所以答案是 0 0 0 。
提交链接
https://hydro.ac/d/lp728/p/20
解析
a a a 的前 k k k 个字符,为连续的。可以采用双指针的思想,第一个指针从 a a a 的第一个字符开始,第二个指针从 b b b 的第一个字符开始。 a a a 的指针一直移动尝试和 b b b 匹配,若一个字符匹配, b b b 的指针才会移动。
另外也可以采取动态规划的思想。
让我们定义 d p i dp_i dpi 为 a a a 的最大前缀,它包含在作为子序列的 b 1 , … , b i b_1,…,b_i b1,…,bi中。
那么转换过程如下
- 如果 b i b_i bi 等于 a [ d p i − 1 + 1 ] a[dp_{i−1}+1] a[dpi−1+1] ,那么 d p i = d p i − 1 + 1 dp_i=dp_{i−1}+1 dpi=dpi−1+1
- 否则为 d p i = d p i − 1 dp_i=dp_{i−1} dpi=dpi−1
答案为 d p m dp_m dpm
参考代码
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
int n , m;
string a , b;
int main()
{cin >> n >> m;cin >> a >> b;a = " " + a , b = " " + b;int sum = 0 , j = 1;for(int i = 1; i <= n; i++){for(; j <= m; j++){if(b[j] == a[i]){sum++;j++;break;}}if(j > m)break;}cout << sum << endl;return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 9;
int n , m , dp[maxn];
string a , b;
int main()
{cin >> n >> m;cin >> a >> b;a = " " + a , b = " " + b;dp[1] = (a[1] == b[1] ? 1 : 0);for(int i = 2; i <= m; i++){if(dp[i - 1] < n && a[dp[i - 1] + 1] == b[i])dp[i] = dp[i - 1] + 1;elsedp[i] = dp[i - 1];}cout << dp[m];return 0;
}