标签:opera 路径 practice long mod cto while codeforce ack
目录
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
7/12 | O | - | O | - | O | - | O | O | - | O | O | - |
签到。
题意:
给出一个\(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;
}
题意:
给出一个序列\(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;
}
代码:
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;
}
题意:
给出\(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;
}
题意:
给出一个字符串,里面只包含‘.‘, ‘#‘:
现在要将该字符串分成若干段,每一段都是上述的某一个,使得分数最大,并且保证字符串中‘#‘的个数不超过\(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;
}
线段树维护矩阵乘法。
代码:
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;
}
2019-2020 ICPC, Asia Jakarta Regional Contest
标签:opera 路径 practice long mod cto while codeforce ack
原文地址:https://www.cnblogs.com/Dup4/p/11888609.html