Contest Info


[Practice Link](https://codeforces.com/contest/1252)

Solved A B C D E F G H I J K L
7/12 O - O - O - O O - O O -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Copying Homework

签到。

C. Even Path

题意:

给出一个\(n \cdot n\)的矩阵,再给出两个长度为\(n\)的序列\(b, c\),并且有\(a_{i, j} = b_i + c_j\),定义一条'Even Path'为一条经过的格子上面都是偶数的路径。

现在每次询问给出\(x_1, y_1, x_2, y_2\),询问\((x_1, y_1) \rightarrow (x_2, y_2)\)是否存在一条'Even Path'

思路:

发现路径的扩展每次都是扩展一行或者一列,那么当且仅当\(b[x_1] \cdots b[x_2]\)这一段数的奇偶性相同并且\(c[x_1] \cdots c[x_2]\)这一段数的奇偶性相同即可。

代码:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, q, a[N], b[N], idA[N], idB[N]; int main() {
while (scanf("%d%d", &n, &q) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
a[i] %= 2;
}
for (int i = 1; i <= n; ++i) {
scanf("%d", b + i);
b[i] %= 2;
}
idA[1] = 1;
idB[1] = 1;
for (int i = 2; i <= n; ++i) {
if (a[i] == a[i - 1]) {
idA[i] = idA[i - 1];
} else {
idA[i] = idA[i - 1] + 1;
}
if (b[i] == b[i - 1]) {
idB[i] = idB[i - 1];
} else {
idB[i] = idB[i - 1] + 1;
}
// cout << idA[i] << " " << idB[i] << endl;
}
int x[2], y[2];
while (q--) {
scanf("%d%d%d%d", x, y, x + 1, y + 1);
if (idA[x[0]] == idA[x[1]] && idB[y[0]] == idB[y[1]]) {
puts("YES");
} else {
puts("NO");
}
}
}
return 0;
}

E. Songwriter

题意:

给出一个序列\(a_i\),要求构造一个序列\(b_i\),满足\(b_i \in [L, R]\),并且\(b_i\)和\(b_{i + 1}\)的大小关系和\(a_i\)与\(a_{i + 1}\)相同

并且满足对于任意\(i \in [1, n - 1]\),都有\(|b_i - b_{i + 1}| \leq K\)。

输出满足要求的字典序最小的\(b_i\)

思路:

令\(l_n = L, r_n = R\),然后往前推出每个\(b_i\)的合法取值范围。

然后从前往后贪心即可。

代码:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, L, R, K, a[N], l[N], r[N]; void gao() {
l[n] = L, r[n] = R;
for (int i = n - 1; i >= 1; --i) {
if (a[i] == a[i + 1]) {
l[i] = l[i + 1];
r[i] = r[i + 1];
} else if (a[i] < a[i + 1]) {
r[i] = r[i + 1] - 1;
l[i] = max(L, l[i + 1] - K);
} else if (a[i] > a[i + 1]) {
l[i] = l[i + 1] + 1;
r[i] = min(R, r[i + 1] + K);
}
if (l[i] > r[i]) {
puts("-1");
return;
}
}
int x = l[1];
for (int i = 1; i <= n; ++i) {
printf("%d%c", x, " \n"[i == n]);
if (i < n) {
if (a[i] < a[i + 1]) {
x = max(l[i + 1], x + 1);
} else if (a[i] > a[i + 1]) {
x = max(x - K, l[i + 1]);
}
}
}
} int main() {
while (scanf("%d%d%d%d", &n, &L, &R, &K) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
gao();
}
return 0;
}

G. Performance Review

代码:

view code
#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f; int n, m, q;
vector<vector<int> >G;
int a[N], rk[N], remind[N]; struct SEG {
struct node {
int Min;
int lazy; node() {} node(int _Min, int _lazy) {
Min = _Min;
lazy = _lazy;
} void up(int x) {
Min += x;
lazy += x;
}
}t[N << 2]; void down(int id) {
int &lazy = t[id].lazy;
if (lazy) {
t[id << 1].up(lazy);
t[id << 1 | 1].up(lazy);
lazy = 0;
}
} void pushup(int id) {
t[id].Min = min(t[id << 1].Min, t[id << 1 |1].Min);
} void build(int id, int l, int r) {
t[id] = {0, 0};
if (l == r) {
t[id].Min = remind[l];
t[id].lazy = 0;
return ;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
} void modify(int id, int l, int r, int ql, int qr, int v) {
if (ql > qr) return ;
if (l >= ql && r <= qr) {
t[id].up(v);
return ;
}
int mid = (l + r) >> 1;
down(id);
if (ql <= mid) modify(id << 1, l, mid, ql, qr, v);
if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr, v);
pushup(id);
} int query(int id, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return t[id].Min;
int mid = (l + r);
down(id);
int res = INF;
if (ql <= mid) res = min(res, query(id << 1, l, mid, ql, qr));
if (qr > mid) res = min(res, query(id << 1 | 1, mid + 1, r, ql, qr));
return res;
}
}seg; int main() {
while (scanf("%d %d %d", &n, &m, &q) != EOF) {
G.clear();
G.resize(m + 1);
rk[1] = 1;
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
if (a[i] > a[1]) {
rk[1]++;
}
}
for (int i = 1, r, b; i <= m; ++i) {
scanf("%d", &r);
rk[i + 1] = rk[i];
for (int j = 1; j <= r; ++j) {
scanf("%d", &b);
G[i].push_back(b);
if (b > a[1]) {
rk[i + 1]++;
}
}
remind[i] = n - r - rk[i];
}
seg.build(1, 1, m);
for (int _q = 1, x, y, z; _q <= q; ++_q) {
scanf("%d %d %d", &x, &y, &z);
int pre = G[x][y - 1], now = z;
if (pre < a[1] && now > a[1]) {
seg.modify(1, 1, m, x + 1, m, -1);
}
if (pre > a[1] && now < a[1]) {
seg.modify(1, 1, m, x + 1, m, 1);
}
int rank = seg.t[1].Min;
puts(rank < 0 ? "0" : "1");
G[x][y - 1] = z;
}
}
return 0;
}

H. Twin Buildings

题意:

给出\(n\)个地基,要造两个占地面积相同(长宽相同)的房子,问最大占地面积是多少。

可以建在两个地基上,也可以建在一个地基上

思路:

  • 建在一个地基上:暴力枚举
  • 建在两个地基上:容易发现,肯定有其中一个地基的一边被完整用上了,那么枚举这一边,然后在从所有最长边大于等于这个变成的地基中按另一边排序选最大和次大来建,这个用堆维护即可

代码:

view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int n, ce;
struct E {
ll x, y; int id;
bool operator < (const E &other) const {
return x < other.x;
}
}e[N]; int main() {
while (scanf("%d", &n) != EOF) {
ce = 0;
for (int i = 1, x, y; i <= n; ++i) {
scanf("%d%d", &x, &y);
e[++ce] = {x, y, i};
e[++ce] = {y, x, i};
}
sort(e + 1, e + 1 + ce);
priority_queue <E> pq;
ll res = 0;
for (int i = ce; i >= 1; --i) {
res = max(res, e[i].x * e[i].y);
ll now = e[i].x;
pq.push({e[i].y, e[i].x, e[i].id});
while (pq.size() > 1) {
E t1 = pq.top(); pq.pop();
E t2 = pq.top(); pq.pop();
if (t1.id == t2.id) {
pq.push(t1);
} else {
pq.push(t1);
pq.push(t2);
break;
}
}
if (pq.size() > 1) {
E t1 = pq.top(); pq.pop();
E t2 = pq.top(); pq.pop();
res = max(res, now * t2.x * 2);
pq.push(t1);
pq.push(t2);
}
}
printf("%lld", res / 2);
puts((res % 2) ? ".5" : ".0");
}
return 0;
}

J. Tiling Terrace

题意:

给出一个字符串,里面只包含'.', '#':

  • 如果拼成'.',那么会得到\(G_1\)的分数
  • 如果拼成'..',那么会得到\(G_2\)的分数
  • 如果拼成'.#.',那么会得到\(G_3\)的分数

现在要将该字符串分成若干段,每一段都是上述的某一个,使得分数最大,并且保证字符串中'#'的个数不超过\(50\)。

但是分段后,要满足第一种类型字符串不超过\(K\)个

思路:

考虑'..'可以换成两个'.',所以\(f[i][j]\)表示前\(i\)个字符,有\(j\)个第三种类型字符串的情况下,最多包含多少个第二类型字符串,然后枚举每种状态贪心即可。

代码:

view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
int n, limit, pre[N], g[3], f[N][60];
char s[N]; ll get(ll x, ll y) {
if (x >= limit || g[0] * 2 <= g[1]) {
x = min(x, 1ll * limit);
return x * g[0] + y * g[1];
}
if (limit - x >= y * 2) {
x += y * 2;
return x * g[0];
}
if ((limit - x) % 2 == 0) {
int need = limit - x;
y -= need / 2;
x += need;
return x * g[0] + y * g[1];
} else {
int need = limit - x - 1;
y -= need / 2;
x += need;
--y;
return x * g[0] + y * g[1] + max(g[0], g[1]);
}
} int main() {
while (scanf("%d%d", &n, &limit) != EOF) {
memset(f, 0, sizeof f);
for (int i = 0; i < 3; ++i) scanf("%d", g + i);
scanf("%s", s + 1);
memset(f, -0x3f, sizeof f);
f[0][0] = 0;
pre[0] = 0;
for (int i = 1; i <= n; ++i) {
pre[i] = pre[i - 1] + (s[i] == '.');
for (int j = 0; j <= 50; ++j) {
f[i][j] = f[i - 1][j];
}
if (i > 1 && s[i] == '.' && s[i - 1] == '.') {
for (int j = 0; j <= 50; ++j) {
f[i][j] = max(f[i][j], f[i - 2][j] + 1);
}
}
if (i > 2 && s[i] == '.' && s[i - 1] == '#' && s[i - 2] == '.') {
for (int j = 0; j <= 50; ++j) {
f[i][j + 1] = max(f[i][j + 1], f[i - 3][j]);
}
}
}
ll res = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= 50 && f[i][j] >= 0; ++j) {
ll now = 1ll * j * g[2];
ll x = pre[i] - (j + f[i][j]) * 2;
ll y = f[i][j];
now += get(x, y);
res = max(res, now);
}
}
printf("%lld\n", res);
}
return 0;
}

K. Addition Robot

线段树维护矩阵乘法。

代码:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
int n, q; char s[N];
struct Matrix {
int a[2][2];
void init() { a[0][0] = a[1][1] = 1; a[0][1] = a[1][0] = 0; }
int* operator[] (int x) { return a[x]; }
Matrix operator * (Matrix b) {
Matrix res;
res[0][0] = (1ll * a[0][0] * b[0][0] % mod + 1ll * a[0][1] * b[1][0] % mod) % mod;
res[0][1] = (1ll * a[0][0] * b[0][1] % mod + 1ll * a[0][1] * b[1][1] % mod) % mod;
res[1][0] = (1ll * a[1][0] * b[0][0] % mod + 1ll * a[1][1] * b[1][0] % mod) % mod;
res[1][1] = (1ll * a[1][0] * b[0][1] % mod + 1ll * a[1][1] * b[1][1] % mod) % mod;
return res;
}
}A, B, res; struct SEG {
struct node {
Matrix a[2];
int lazy;
void init() {
a[0].init(); a[1].init();
lazy = 0;
}
void up() {
swap(a[0], a[1]);
lazy ^= 1;
}
}t[N << 2];
void pushup(int id) {
t[id].a[0] = t[id << 1 | 1].a[0] * t[id << 1].a[0];
t[id].a[1] = t[id << 1 | 1].a[1] * t[id << 1].a[1];
}
void down(int id) {
int &lazy = t[id].lazy;
if (lazy) {
t[id << 1].up();
t[id << 1 | 1].up();
lazy = 0;
}
}
void build(int id, int l, int r) {
if (l == r) {
t[id].a[0] = A;
t[id].a[1] = B;
if (s[l] == 'B') {
swap(t[id].a[0], t[id].a[1]);
}
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
void modify(int id, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) {
t[id].up();
return;
}
int mid = (l + r) >> 1;
down(id);
if (ql <= mid) modify(id << 1, l, mid, ql, qr);
if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr);
pushup(id);
}
Matrix query(int id, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return t[id].a[0];
int mid = (l + r) >> 1;
down(id);
Matrix res; res.init();
if (qr > mid) res = res * query(id << 1 | 1, mid + 1, r, ql, qr);
if (ql <= mid) res = res * query(id << 1, l, mid, ql, qr);
return res;
}
}seg; int main() {
A = {1, 1, 0, 1};
B = {1, 0, 1, 1};
while (scanf("%d%d", &n, &q) != EOF) {
scanf("%s", s + 1);
seg.build(1, 1, n);
int op, l, r, a, b;
for (int i = 1; i <= q; ++i) {
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
seg.modify(1, 1, n, l, r);
} else {
scanf("%d%d", &a, &b);
res = {a, 0, b, 0};
res = seg.query(1, 1, n, l, r) * res;
printf("%d %d\n", res[0][0], res[1][0]);
}
}
}
return 0;
}

最新文章

  1. sql 中 left join 的使用
  2. Java Io 流(输入输出流)
  3. 巧用jquery实现提交(submit)表单时候验证文本框是否为空
  4. data-属性
  5. (转载)Java基础知识总结
  6. 关于Warn:name or service not known的解决办法
  7. IIS配置及防黑
  8. redis知识
  9. php第二季
  10. xml转义符
  11. Python爬虫从入门到放弃(二十)之 Scrapy分布式原理
  12. zookeeper curator处理会话过期session expired
  13. jsp内置对象 的使用范围和类型【说明】
  14. JAVA有哪些数据类型?基本数据类型各占多少个字节
  15. [翻译]理解分析Linux里的101个ELF文件
  16. 【BZOJ5302】[HAOI2018]奇怪的背包(动态规划,容斥原理)
  17. 富文本编辑器Ueditor 及 hibernate 逆向工程
  18. nginx 配置后网站图片加载出来一半或者不出来
  19. anaconda的spyder打不开
  20. WebSocket协议详解

热门文章

  1. 编译内核提示mkimage command not found – U-Boot images will not be built
  2. 匹配script标签及内容js代码的正则表达式
  3. 2..net core 和.net framework 版本
  4. C#在txt类文件中追加内容
  5. 图片上传怎么用File接受文件
  6. axios配置及使用(发起请求时带上token)
  7. 【日语】日语N5学习
  8. SDL -安全开发生命周期
  9. SQL SERVER-JOB搬迁脚本
  10. Elasticsearch vs Solr 搜索引擎对比和选型