2025.5.14
刷题日记
今天是板刷1600的第一天
艰难的A掉了三道题,两道1600,一道1700
第一道题是一道1700的字符串 + dp,是EDU_178的E题
https://codeforces.com/contest/2104/problem/E
瞪了半天愣是一点思路都没有,只好直接去学习题解了(
这道题是说,对于给定的字符串s,有q次查询,每次输入一个字符串t
去判断t最少需要加多少个字符,可以不再是s的子串
其实暴力是很好写的,但奈何 q <= 2e5,故需要对其进行预处理
题解中很巧妙用了一个next数组去实现这个事情,其中next[i, j]表示第i位后字符j第一次出现的位置
最后用dp去求了一遍,时间复杂度O(nk)
点击查看代码
#include <bits/stdc++.h>
using ll = long long;
const int N = 1e5 + 10;
#define INF 0x3f3f3f3f
void solve () {
int n, k;
std::cin >> n >> k;
std::string s;
std::cin >> s;
std::vector next(n + 2, std::vector<int>(k, n));
std::vector<int> f(n + 1, 0);
for (int i = n - 1; i >= 0; i--) {
next[i] = next[i + 1];
int max = *max_element(next[i].begin(), next[i].end());
f[i] = f[max] + 1;
next[i][s[i] - 'a'] = i;
}
// debug2(next, 0, n - 1, 0, k - 1);
// debug1(f, 0, n - 1);
int q;
std::cin >> q;
while (q--) {
std::string t;
std::cin >> t;
int id = -1;
for (int i = 0; i < t.size(); i++) {
id = next[id + 1][t[i] - 'a'];
}
std::cout << f[id] << '\n';
}
}
int main () {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
// std::cin >> t;
while (t--) {
solve();
}
return 0;
}
第二题是一道1600的思维题,Rround_1019的C题
https://codeforces.com/contest/2103/problem/C
这道题的意思是,对于给定的数组,要求将其划分成三个子数组
然后取这三个子数组的中位数构成一个序列,在取这个序列的中位数
这个最终的中位数如果小于等于k,则YES,反之NO
这道题同样是没啥思路,但相对于上面那道1700,也不是那么的拼尽全力无法战胜
不过话虽如此,博主最终还是没有战胜(
去看了题解,发现这个思维简直惊为天人(对思维不好的博主来说)
对于给定的数组a[]和数字k,有a[i] = k <= n ? 1 : -1;
意思就是,如果a[i] > k, 那么a[i] = -1, 反之a[i] = -1
因为题目要求最终的中位数小于等于k嘛,那这样一来,对于一个连续区间
如果他们的和为负数,那么他们的中位数就一定大于k
只要三个连续区间有两个区间的和为正数,那么最终的中位数就一定小于k!
(这个简化的思路真的令博主心服口服)
点击查看代码
#include <bits/stdc++.h>
using ll = long long;
const int N = 1e5 + 10;
#define INF 0x3f3f3f3f
void solve () {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
int x;
std::cin >> x;
a[i] = x <= k ? 1 : -1;
}
// Condition 1
int sum1 = 0, sum2 = 0;
int flag1 = 0, flag2 = 0;
for (int i = 1; i <= n; i++) {
sum1 += a[i];
if (sum1 >= 0) {
flag1 = i;
break;
}
}
for (int i = n; i >= 1; i--) {
sum2 += a[i];
if (sum2 >= 0) {
flag2 = i;
break;
}
}
if (flag1 && flag2 && flag1 < flag2) {
std::cout << "YES\n";
return;
}
// Condition 2
sum1 = 0;
for (int i = 1; i <= n; i++) {
sum1 += a[i];
if (sum1 >= 0) {
sum2 = 0;
for (int j = i + 1; j <= n; j++) {
sum2 += a[j];
if (sum2 >= 0 && i < j && j < n) {
std::cout << "YES\n";
return;
}
}
}
}
// Condition 3
sum1 = 0;
for (int i = n; i >= 1; i--) {
sum1 += a[i];
if (sum1 >= 0) {
sum2 = 0;
for (int j = i - 1; j >= 1; j--) {
sum2 += a[j];
if (sum2 >= 0 && i > j && j > 1) {
std::cout << "YES\n";
return;
}
}
}
}
std::cout << "NO\n";
}
int main () {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
第三题是一道1600的思维题,偏数学一点
是Round_796的A题,一场Div.1
https://codeforces.com/problemset/problem/1687/A
这道题讲的是,对于一个长度为n的序列,有k秒的限制,每次到达一个位置时,会取走这个位置上的数字加到sum上
其中的每个数字每过一秒都会+1,求sum的最大值
这次博主不再直接read题解了
在硬刚一个多小时后,成功推出了一半的正解(
其实无非就是两种情况,n >= k 和 n < k
对于n >= k,那么显然序列中所有的数字都会取过一遍
对于n < k,那么只能取其中长度为k且区间和最大的区间了
思路其实是很简单的,但博主属实是被这个1600给吓住了(
没能独立的A掉真是抱歉
点击查看代码
#include <bits/stdc++.h>
using ll = long long;
const int N = 2e5 + 10;
#define INF 0x3f3f3f3f
void solve () {
ll n, k;
std::cin >> n >> k;
std::vector<ll> a(n + 1);
std::vector<ll> sum(n + 1, 0);
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
// debug1(sum, 1, n);
ll ans = 0;
if (k >= n) {
for (int i = 1; i <= n; i++) {
ans += a[i];
}
ans = ans + n * k - n * (n + 1) / 2;
}
else {
for (int i = 1; i + k - 1 <= n; i++) {
ll tmp = sum[i + k - 1] - sum[i - 1] + k * (k - 1) / 2;
ans = std::max(ans, tmp);
}
}
std::cout << ans << '\n';
}
int main () {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}