【CF】Day47——Educational Codeforces Round 178 (Rated for Div. 2) E
这场A-E真的简单,E题稍微卡了一会,还需要dp优化
E. Unpleasant Strings
题目:
思路:
很有学习价值的一题
这题有两个难点,第一是如何快速判断一个 t 是不是 s 的子序列,第二个是如何快速多次查找最小添加数量
我们先来解决第一个,由于要是 s 的子序列,那我们肯定要找到 t 的第一个字符在 s 中最前的位置,然后第二个字符在 s 中最前的位置(且要在第一个字符的位置之后),那么这样的查找我们怎么优化呢?如果每次循环一遍字符串肯定是不行的,所以我们要想一个快速的查找位置的方法,我们观察到每次查找都是比上一个位置大,即具有单调性,那么对于这种问题我们显然可以使用二分查找来写,因此我们记录一个数组 f[i],其代表 i 字符的位置有哪些,那么查找过程就很明显可以写出来了,我们枚举每个位置,并且选择第一个比之前位置大的合法位置,如果找不到,说明这个字符串不是子序列,否则必定是
那么找子串结束了,接下来如何快速知道要几个字符呢?
这里我直接给出我最后的优化方法,我们在判断是否合法时我们能知道子串最后一个字符对应的哪里,我们希望越快得出结果最好,那么我们可以考虑如果我们能在 O(1) 的复杂度里得出来不就很完美吗,我们观察一下,对于同一个位置我们最好的添加方式其实可以从后面的状态转移过来,比如对于 bcb,我们之后添加的方式可能是 bcba bcbb bcbc ,那我们只需要选择里面需要添加次数最少的可能即可,那么对于 bcb 的答案就是 min(bcba bcbb bcbc) + 1
那么其实答案就出来了,我们可以定义 dp[i] 为当前字符串结尾在 i 处时所需要的最小花费,那么显然转移就是 dp[i] = min(dp[j] + 1) 其中 j 就是后续添加 26 种字符之后的位置的可能,特别注意可能为 0,所以记得判断一下
具体实现看代码
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
int n, k;
string s;
vector<vector<int>> f(30);
vector<int> dp(1000006,(int)1e9);
void Init()
{for (int i = 0; i < n; i++){f[s[i] - 'a'].push_back(i);}for (int i = n - 1; i >= 0; i--){for (int j = 0; j < k; j++){auto it = upper_bound(f[j].begin(), f[j].end(), i);if (it == f[j].end()){dp[i] = 1;break;}dp[i] = min(dp[i], dp[*it] + 1);}}
}int getPos(const string& t)
{int temppos = -1;for (auto c : t){auto it = upper_bound(f[c - 'a'].begin(), f[c - 'a'].end(), temppos);if (it == f[c - 'a'].end()){return -1;}temppos = *it;}return temppos;
}
void solve()
{int q;cin >> q;for (int i = 0; i < q; i++){string t; cin >> t;if (getPos(t) == -1){cout << 0 << endl;continue;}cout << dp[getPos(t)] << endl;}
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){cin >> n >> k;cin >> s;Init(); solve();}return 0;
}