「赛后总结」Codeforces Round #687 (Div. 2)
作者:互联网
题意 & 题解
A.Prison Break
题意:
在二维平面中找到距离一个点最大的曼哈顿距离。
题解:
一定在矩阵的四个角上。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 100001
#define inf 2147483647
typedef long long ll;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
inline void read(int &T) {
int x = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
T = f ? -x : x;
}
int t, n, m, r, c;
int main() {
read(t);
while (t--) {
int ans = 0;
read(n), read(m), read(r), read(c);
ans = max(ans, abs(1 - r) + abs(1 - c));
ans = max(ans, abs(n - r) + abs(1 - c));
ans = max(ans, abs(1 - r) + abs(m - c));
ans = max(ans, abs(n - r) + abs(m - c));
printf("%d\n", ans);
}
return 0;
}
B.Repainting Street
题意:
给出 \(n\) 个点和一个参数 \(k\),每个点有一个颜色 \(a_i\),每次可以选择一段长为 \(k\) 的区间任意修改其中的颜色,问最少选择多少段使得颜色全部一致。
\(1\le a_i \le 100\),\(1 \le n \le 10^5\)
题解:
枚举改成什么颜色,然后贪心的选择区间,时间复杂度 \(O(n\max(a_i))\)。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 100001
#define inf 2147483647
typedef long long ll;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
inline void read(int &T) {
int x = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
T = f ? -x : x;
}
int t, n, k, ans, a[M];
int main() {
read(t);
while (t--) {
read(n), read(k); ans = inf;
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= 100; ++i) {
int tot = 0, last = -1;
for (int j = 1; j <= n; ++j) {
if (a[j] == i) continue;
if (last == -1) ++tot, last = j;
else {
if (last + k - 1 >= j) continue;
else last = j, ++tot;
}
}
ans = min(ans, tot);
}
printf("%d\n", ans);
}
return 0;
}
C.Bouncing Ball
题意:
给一个长为 \(n\) 的 \(01\) 串,可以进行两种操作:
-
花费 \(y\) 的时间从最前面删去一个字符
-
花费 \(x\) 的时间将一个 \(0\) 变成 \(1\)。
问最少多少时间之后 \(p,p+k,p+2k,\dots,p+qk\),其中 \(q\) 是最大的正整数使得 \(p+qk \le n\),都是 \(1\)。
题解:
从前面删去一个字符相当于让 \(p\) 往后移了一个位置,所以可以计算出从 \(p,p+1,\dots,n\) 开始的时间花费。
从 \(x\) 的位置则需要删除 \(x - p\) 个字符,时间花费为 \((x - p) \times y\)。
然后计算 \(x,x+k,x+2k,\dots,x+qk\) 位置上有 \(cnt_0\) 个字符 \(0\),时间花费为 \(cnt_0 \times x\)。
用 \(ans_i\) 表示从 \(i\) 开始的 \(cnt_0\)。
发现 \(j\) 位置如果为 \(0\),会对所有 \((x - p)\bmod k = (j-p) \bmod k\) 的 \(x\) 有贡献,可以从后往前 \(O(n)\) 处理出 \(ans\) 数组。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 100001
#define inf 2147483647
typedef long long ll;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
inline void read(int &T) {
int x = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
T = f ? -x : x;
}
std::string s;
int t, n, p, k, x, y, ans[M];
int main() {
read(t);
while (t--) {
read(n), read(p), read(k);
std::cin >> s;
read(x), read(y);
int len = s.length(), minn = inf;
for (int i = len - 1; i >= p - 1; --i) {
int j = i + 1;
if (s[i] == '1') {
minn = min(ans[(j - p) % k] * x + (j - p) * y, minn);
}
else {
++ans[(j - p) % k];
minn = min(ans[(j - p) % k] * x + (j - p) * y, minn);
}
}
std::cout << minn << '\n';
memset(ans, 0, sizeof ans);
}
return 0;
}
D.XOR-gun
题意:
给定一个不减的序列,每次可以选择两个相邻的数将这两个数替换为他们的异或值,序列的长度减一,问最少几次操作可以使这个序列不再满足不减。
题解:
对于三个相邻的二进制最高位相同的数可以选择后两个异或起来即可,因此想要原数列中不出现这样的情况长度不能超过 \(60\),如果超过 \(60\) 直接输出 \(1\)。
否则暴力。
经过多次操作之后一定是将 \(i\sim j\),\((j+1)\sim k\) 的异或和相比较,枚举 \(i,j,k\),时间复杂度 \(O(n^3)\)
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 100001
#define inf 2147483647
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
int n, ans = inf, a[M], sxor[M];
int main() {
scanf("%d", &n);
if (n >= 100) { puts("1"); return 0; }
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
sxor[i] = sxor[i - 1] ^ a[i];
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= i; ++j) {
for (int k = i + 1; k <= n; ++k) {
if ((sxor[i] ^ sxor[j - 1]) > (sxor[k] ^ sxor[i])) {
ans = min(ans, k - i - 1 + i - j);
}
}
}
}
if (ans == inf) puts("-1");
else printf("%d\n", ans);
return 0;
}
E.New Game Plus!
题意:
初始分数为 \(0\),奖励值为 \(0\),有 \(n\) 个 \(boss\),每个 \(boss\) 有一个增量 \(a_i\),打死一个 \(boss\) 后可以给分数加上现在的奖励值,并给奖励值加上 \(boss\) 的增量,你最多可以 \(k\) 次将奖励值变成 \(0\)。问能获得的最大得分。
题解:
题目可以转化成将 \(n\) 个 \(boss\) 分成 \(k+1\) 组。每组都是独立的。
对于每一组都按 \(boss\) 的增量降序排列为 \(b_1,b_2,\dots,b_m\)。
能获得的分数为 \((m-1)b_1+(m-2)b_2+\dots +b_{m-1}\)。
将 \(k-1\) 个零放到单调队列里,按增量从大到小枚举 \(boss\),从单调队列中取出最大的数加到分数中并把最大的数加上当前增量放到单调队列中。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#define M 500001
typedef long long ll;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
ll ans;
int n, k, a[M];
std::priority_queue<ll> q;
inline void read(int &T) {
int x = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
T = f ? -x : x;
}
bool cmp(int a, int b) { return a > b; }
int main() {
read(n), read(k);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= k + 1; ++i) q.push(0);
std::sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; ++i) {
ll u = q.top(); q.pop();
ans += u, q.push(u + a[i]);
}
std::cout << ans << '\n';
return 0;
}
rating & 总结
没有 rating。
我不太行/kk
标签:return,min,int,Codeforces,ans,687,include,Round,define 来源: https://www.cnblogs.com/poi-bolg-poi/p/14060114.html