[每日随题6] 模拟 - 贪心 - KMP、DP
整体概述
- 难度:1200 \(\rightarrow\) 1600 \(\rightarrow\) 2000
1185B.Email from Polycarp
-
标签:模拟
-
前置知识:无
-
难度:Div2.B 1200
题目描述:

输入格式:

输出格式:

样例输入:
4
hello
hello
hello
helloo
hello
hlllloo
hello
helo
5
aa
bb
codeforces
codeforce
polycarp
poolycarpp
aaaa
aaaab
abcdefghijklmnopqrstuvwxyz
zabcdefghijklmnopqrstuvwxyz
样例输出:
YES
YES
NO
NO
NO
NO
YES
NO
NO
解题思路:
-
由于每个字母可以被连续打多次,我们本质只需要检测同一个字母被打印的次数是不是更多即可。
-
如
hello可以看作h:1,e:1,l:2,o:1,那么我们只需检测字母是否依次出现,且被打印的次数更多即可。 -
从左到右模拟一遍即可
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 5e5+5;
inline string solve(){
string a,b; cin >> a >> b;
int i,j;
for(i=0,j=0;i<Size(a) && j<Size(b);i++,j++){
int cnta = 1, cntb = 1;;
while(i+1<Size(a) && a[i+1] == a[i]) i++,cnta++;
while(j+1<Size(b) && b[j+1] == b[j]) j++,cntb++;
if(b[j] != a[i] || cntb < cnta) return "NO";
}
if(i == Size(a) && j == Size(b)) return "YES";
return "NO";
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; cin >> T;
while(T--) cout << solve() << '\n';
return 0;
}
1861C.Queries for the Array
-
标签:贪心
-
前置知识:无
-
难度:Div.2.C 1600
题目描述:

输入格式:
-
输入的第一行包含一个整数 \(t\) \((1\le t\le 10^4)\) 表示测试用例数。
每个测试用例包含一行字符串 \(s\) \((1\le |s| \le 2⋅10^5)\)。该字符串由
0、1、+和-字符组成。 -
输入的其他限制:对于 \(s\) 的每个前缀,其
+字符的个数不少于-字符的个数。所有测试用例中 \(|s|\) 的总和不超过 \(2⋅10^5\)。
输出格式:
-
对于每个测试用例,如果 Monocarp 可以执行查询,从而使他所写的字符序列恰好是 \(s\),则打印
YES。否则,打印NO。 -
输出对
YES和NO大小写不敏感。
样例输入:
7
++1
+++1--0
+0
0
++0-+1-+0
++0+-1+-0
+1-+0
样例输出:
YES
NO
NO
NO
YES
NO
NO
解题思路:
-
首先我们知道,尽可能让无序的位置最少对后续位置的影响最少。
-
只要先前某个位置出现过了无序,那么我们后续再查询 \(0\) 均可以满足,所以我们只需要记录下出现无序的位置为 \(unorder\)。
-
其次我们需要记录哪一部分序列已经有序,每当出现一个 \(1\) 的时候,相当于把当前的序列确定为有序了,我们记录下有序的序列的末位为 \(order\)。
-
我们再记录下当前的序列长度为 \(cnt\),那么当出现一个
+时,我们只需要将 \(cnt\) 加 \(1\) 即可,因为新加入的这个数字的大小我们无法确定,需要由后续的查询来将其确定。 -
出现一个
-的时候,我们将 \(cnt\) 减 \(1\),如果此时的 \(order\gt cnt\),则将 \(order\) 值为 \(cnt\),若此时的 \(unorder\gt cnt\),说明此时整个序列没有确定需要无序的位置了,将 \(unorder\) 置为 \(0\)。 -
出现一个 \(0\) 的时候,若 \(order = cnt\) 或者 \(cnt \lt 2\),则整个序列有序,返回非法。否则若 \(unorder = 0\) 则将 \(unorder\) 置为当前 \(cnt\)。
-
出现一个 \(1\) 的时候,若 \(unorder\ne 0\) 返回非法。否则将 \(order\) 置为当前 \(cnt\)。
-
从左到右模拟一遍即可。
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
inline string solve(){
string s; cin >> s;
int cnt = 0,order = 0,unorder = 0;
for(auto x:s){
if(x == '+') ++cnt;
if(x == '-'){
--cnt;
if(unorder > cnt) unorder = 0;
order = min(order,cnt);
}
if(x == '0'){
if(order == cnt || cnt < 2) return "NO";
if(!unorder) unorder = cnt;
}
if(x == '1'){
if(unorder) return "NO";
order = cnt;
}
}
return "YES";
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; cin >> T;
while(T--) cout << solve() << '\n';
return 0;
}
346B.Lucky Common Subsequence
-
标签:KMP、线性DP
-
前置知识:无
-
难度:Div.1.B 2000
题目描述:

输入格式:

输出格式:

样例输入:
AJKEQSLOBSROFGZ
OVGURWZLWVLUXTH
OZ
AA
A
A
样例输出:
ORZ
0
解题思路:
-
与 \(LCS\) 相似,原先定义 \(dp\) 数组 \(dp_{i,j}\) 使用第一个字符串前 \(i\) 个,第二个字符串前 \(j\) 个,的最长公共子序列。那么现在增加了一个串 \(virus\),我们也需要对应地增加一维,定义 \(dp_{i,j,k}\) 表示,使用前一个串前 \(i\) 个,第二个串前 \(j\) 个,匹配了 \(virus\) 串前 \(k\) 个字符的最长公共子序列。
-
那么我们需要考虑如何转移,若 \(a_i = b_j\),原先匹配到 \(virus\) 的前 \(k\) 个,那么我们需要考虑增加一个 \(a_i\) 会匹配上 \(virus\) 多长的前缀。
我们可以使用 \(KMP\) 的 \(fail\) 数组来加速这个匹配的过程,快速找到最大的 \(t\) 使得 \(virus\) 前 \(k\) 个字符加上 \(a_i\) 可以匹配上 \(virus\) 的前 \(t\) 个字符。
那么此时 \(dp_{i,j,t} \leftarrow dp_{i-1,j-1,k}+a_i\)。
-
同时无论 \(a_i\) 是否等于 \(b_j\),都有 \(dp_{i,j,k} \leftarrow max(dp_{i-1,j,k},dp_{i,j-1,k})\)。
-
那么我们提前预处理出 \(virus\) 串的 \(fail\) 数组,随后暴力 \(dp\),最后统计所有答案中的最大值即可。
-
总复杂度 \(O(n^4)\)。
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 105;
string a,b,c,dp[N][N][N];
int fail[N];
inline string& Cmax(string &x,string y){
if(Size(x)<Size(y)) x = y;
return x;
}
inline void solve(){
cin >> a >> b >> c;
for(int i=1,j=0;i<Size(c);i++){
while(j && c[i]!=c[j]) j=fail[j];
j += c[i] == c[j];
fail[i+1] = j;
}
for(int i=1;i<=Size(a);i++){
for(int j=1;j<=Size(b);j++){
for(int k=0;k<Size(c);k++){
Cmax(Cmax(dp[i][j][k],dp[i-1][j][k]),dp[i][j-1][k]);
if(a[i-1] == b[j-1]){
int t = k;
while(t && c[t] != a[i-1]) t = fail[t];
t += c[t] == a[i-1];
Cmax(dp[i][j][t],dp[i-1][j-1][k]+a[i-1]);
}
}
}
}
string ans = "";
for(int i=0;i<Size(c);i++) Cmax(ans,dp[Size(a)][Size(b)][i]);
if(Size(ans) == 0){ cout << 0; return;}
cout << ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; T = 1;
while(T--) solve();
return 0;
}

简单的三题字符串,练手吖~
浙公网安备 33010602011771号