[每日随题6] 模拟 - 贪心 - KMP、DP

整体概述

  • 难度:1200 \(\rightarrow\) 1600 \(\rightarrow\) 2000

1185B.Email from Polycarp

  • 标签:模拟

  • 前置知识:无

  • 难度:Div2.B 1200

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

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:1e:1l:2o: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

题目描述:

image

输入格式:

  • 输入的第一行包含一个整数 \(t\) \((1\le t\le 10^4)\) 表示测试用例数。

    每个测试用例包含一行字符串 \(s\) \((1\le |s| \le 2⋅10^5)\)。该字符串由 01+- 字符组成。

  • 输入的其他限制:对于 \(s\) 的每个前缀,其 + 字符的个数不少于 - 字符的个数。

    所有测试用例中 \(|s|\) 的总和不超过 \(2⋅10^5\)

输出格式:

  • 对于每个测试用例,如果 Monocarp 可以执行查询,从而使他所写的字符序列恰好是 \(s\),则打印 YES。否则,打印 NO

  • 输出对 YESNO 大小写不敏感。

样例输入:

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

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

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;
}

posted @ 2025-07-13 17:41  浅叶梦缘  阅读(15)  评论(0)    收藏  举报