文章目录
Codeforces Round #689 (Div. 2, based on Zed Code Competition)
A. String Generation
题意: 意思是要你给一个由abc组成的字符串,要求长度为n,其中最长回文子串为k。
题解: 要最长回文子串为k,那么使得最长回文子串为0就好了
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
int n, m, T;
int main() {
cin >> T;
while(T--) {
cin >> n >> m;
string res = "";
int len = n / 3;
for (int i = 1; i <= len; ++i) res += "abc";
int rem = n % 3;
if (rem == 1) res += "a";
else if (rem == 2) res += "ab";
cout << res << endl;
}
return 0;
}
B.Find the Spruce
题意: 给一个n*m的网格,每个点为* 或者 . ,问最多构成几个等腰三角形
题解: dp[i][j] = min(dp[i + 1][j - 1], min(dp[i + 1][j], dp[i + 1][j + 1])) + 1
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, m, res[1000][1000];
char mp[1000][1000];
int main() {
cin >> t;
while (t--) {
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> mp[i][j];
res[i][j] = 0;
}
}
LL anss = 0;
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < m; j++) {
if (mp[i][j] == '*') {
res[i][j]++;
if (i != (n - 1) && (j != 0) && (j != m - 1)) {
int temp = 0;
temp = min(res[i + 1][j],
min(res[i + 1][j - 1], res[i + 1][j + 1]));
if (temp) res[i][j] += temp;
}
}
anss += res[i][j];
}
}
cout << anss << endl;
}
return 0;
}
C. Random Events
题意: 给定n个数字,分别为1~n的全排列。给定m个操作,每次操作给定r,p,分别表示有p的概率能够使得a[1 ~ r]有序。问经过m次操作,能够使得整个数组有序的概率是多少?
题解: 考虑将[r, p]结构体按照r从小到大排序,那么必然要倒着往前看,如果当前区间[1 ~ ri]能够成功排序,那么需要乘上p,否则乘上失败的概率(1 - p)继续往前看。
按照上面的处理会很复杂,其实根本不需要,概率题很多时候可以直接考虑1 - 失败的概率。
我们可以维护失败的概率。首先倒着往前看,找到第一个a[i] != i的位置pos。然后如果要失败,只需要满足r >= pos,因为如果r < pos,必然失败,那就乘上概率1,不需要考虑。然后每次如果r >= pos,那么乘上(1 - p)。最后答案为1 - res
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const MAXN = 2e5 + 10;
int n, m, T, a[MAXN];
int main() {
cin >> T;
while(T--) {
cin >> n >> m;
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
int pos = n;
while(pos > 0 && a[pos] == pos) pos--;
double res = 1.0;
for (int i = 1; i <= m; ++i) {
int r;
double p;
cin >> r >> p;
if (r >= pos) res *= (1 - p);
}
if (pos == 0) res = 0;
printf("%.10lf\n", 1 - res);
}
return 0;
}
D. Divide and Summarize
题意: 给你一个数组,设mid=(数组中最大元素+最小元素)/2,你可以把小于等于mid的数放在一堆,大于mid的数放在一堆形成两个新的数组。同样,新形成的两个数组也可以进行相同操作。给你一堆询问,每次询问给出一个数,问是否有通过这样方式构造的数组的元素和等于这个数。
题解: 只需要将所有的情况得到的值存储起来,然后在之后的问询阶段判断是否有这个值就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
int n, m, T, a[N];
LL sum[N];
set<LL> s;
void dfs(int l, int r) {
if (l > r) return;
LL this_sum = 0;
if (!l) this_sum = sum[r];
else this_sum = sum[r] - sum[l - 1];
s.insert(this_sum);
if (l == r) return;
int mid = (a[l] + a[r]) / 2;
int pos = upper_bound(a + l, a + r + 1, mid) - a;
if (pos == r + 1 || pos == l) {
return;
}
pos--;
dfs(l, pos);
if (pos <= r) dfs(pos + 1, r);
}
int main() {
cin >> T;
while(T--) {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
sort(a, a + n);
for (int i = 0; i < n; ++i) {
if (!i) sum[i] = a[i];
else sum[i] = sum[i - 1] + a[i];
}
s.clear();
dfs(0, n - 1);
for (int i = 1; i <= q; ++i) {
LL query;
scanf("%lld", &query);
if (!s.count(query)) puts("No");
else puts("Yes");
}
}
return 0;
}
E. Water Level
题意: 初始在饮水机中有k升水,每天需要消耗x升水,每天的一开始,John可以选择往饮水机中加y升水(可以不加)。问t天内是否能保证每时每刻饮水机内的水大于等于l升,小于等于r升。即k ′ ∈ [ l , r ]
题解: 这个大佬的题解讲的很明白了。主要的就是要注意到x的范围,然后分类讨论。https://blog.csdn.net/sigh_/article/details/111064024
以下是引用这个大佬的博客内容:
因为饮水机中的水都是要求在 [ l , r ] 内,可以从 k − = l , r − = l,这样就能忽略 l l l的影响(从k升水中扣除l升水,该部分不可用)。 除了x,所有的数据范围都在1e18,所以可以考虑从x入手,分类讨论:
若 x > y,显然水位每天都会下降。此时考虑水能够多少天使用,常规状态下每天减少 ( x − y ) 升水,注意第一天能否加水,和第一天的水是否够用。
若 x ≤ y , 让饮水机中的水尽量少,如果够一天的使用,则不加水,如果不够一天的使用则加水。设k为饮水机中的剩余水量。当 k<x时,则必须加水:
若 k + y > r,不能加水,无解。
若 k + y ≤ r ,能加水,则 k + = y ,计算当前水能用几天,并且 k % = x,若k在之前中的计算中出现过,则说明这些操作形成了循环,能保证水量一直在 [ 0 , r ] 间,则有解。
若 t ≤ 0 ,退出循环,则有解。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const MAXN = 2e5 + 10;
int n, m, T;
unordered_map<LL, int> mp;
// x消耗,y添加,k一开始
int check(LL k, LL r, LL t, LL x, LL y) {
if (x > y) {
LL day = 0;
if (k + y > r) {
if (k < x) day = 0;
else day = 1 + (k - x) / (x - y);
}
else day = k / (x - y);
return day >= t;
}
else {
t -= k / x;
k = k % x;
mp[k] = 1;
while(t > 0) {
if (k + y > r) return 0;
t -= (k + y) / x;
k = (k + y) % x;
if (mp.count(k)) return 1;
mp[k] = 1;
}
return 1;
}
}
int main() {
LL k, l, r, t ,x, y;
cin >> k >> l >> r >> t >> x >> y;
if (check(k - l, r - l, t, x, y)) puts("Yes");
else puts("No");
return 0;
}