CF1083(Round #526 Div. 1) 简要题解
题目链接
https://codeforces.com/contest/1083
题解
A. The Fair Nut and the Best Path
可以忽略掉“任意时刻油量非负”这一条件,直接在原树上找一条点权和减去边权和最大的路径。因为若一种方案包含了一段从起点出发,到某个结点时油量为负数的路径,那么删掉这一段路径必然会使得最终答案更优。
这样直接在原树上做一遍 \(O(n)\) 的 dp 即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
void cmax(long long& x, long long y) {
if (x < y) {
x = y;
}
}
int n, w[N];
long long f[N], answer;
vector<pair<int, int>> graph[N];
void dfs(int u, int father) {
f[u] = w[u];
for (auto e : graph[u]) {
if (e.first != father) {
dfs(e.first, u);
cmax(answer, f[u] - e.second + f[e.first]);
cmax(f[u], w[u] - e.second + f[e.first]);
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &w[i]);
cmax(answer, w[i]);
}
for (int i = 1; i < n; ++i) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
graph[u].emplace_back(v, c);
graph[v].emplace_back(u, c);
}
dfs(1, 0);
printf("%lld\n", answer);
return 0;
}
B. The Fair Nut and Strings
考虑一个暴力的做法,将所有合法的字典序不小于 \(s\) 同时不大于 \(t\) 的字符串插入到一棵 trie 当中。显然,若 trie 的第 \(i\) 层共包含了 \(x_i\) 个结点,那么我们一定能取到 \(\min\{k, x_i\}\) 种不同的长度为 \(i\) 的前缀,因此答案即为 \(\sum_\limits{i = 1}^n \min\{k, x_i\}\)。\(x_i\) 可以直接递推,因此可以在 \(O(n)\) 的时间内完成答案的统计。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, k;
char a[N], b[N];
int main() {
scanf("%d%d%s%s", &n, &k, a + 1, b + 1);
int all = 1;
long long answer = 0;
for (int i = 1; i <= n; ++i) {
all = min((long long) all << 1, (long long) INT_MAX);
if (a[i] == 'b') {
--all;
}
if (b[i] == 'a') {
--all;
}
answer += min(all, k);
}
printf("%lld\n", answer);
return 0;
}
C. Max Mex
令 \({\rm pos}_i(i \in [0, n - 1])\) 表示权值 \(i\) 所在结点的编号。考虑构建一棵线段树,线段树的每个结点 \([l, r]\) 记录 \({\rm pos}_l, {\rm pos}_{l + 1}, \cdots , {\rm pos}_r\) 这些结点在树上所在的最短的简单链的两个端点 \((u, v)\),特殊地,若这些结点无法位于同一条简单链上,那么记为 \((-1, -1)\)。
在线段树向上合并结点信息时,我们需要判断当前线段树结点的两个子结点所对应的链 \((u_1, v_1)\) 与 \((u_2, v_2)\) 是否能合并成一条新的简单链,即判断是否能从这四个结点中选出两个结点,使得另外的两个结点均在选出的两个结点间的路径上。记结点 \(u, v\) 在树上的最近公共祖先为 \(p\),那么一个结点 \(x\) 在结点 \(u, v\) 间的路径上当且仅当满足 \({\rm lca}_{u, x} = x\) 或 \({\rm lca}_{v, x} = x\),同时 \({\rm lca}_{x, anc} = p\)。使用 RMQ 求 \({\rm lca}\) 可以在 \(O(1)\) 的时间内完成判断,因此单次信息合并的时间复杂度为 \(O(1)\),但常数很大(最坏情况一次信息合并可能有 \(\binom{4}{2} \times 7 = 42\) 次 \({\rm lca}\) 的查询)。
注意若存在一个子结点的链信息为 \((-1, -1)\),那么显然当前线段树结点的链信息也应记为 \((-1, -1)\)。
每一次修改操作直接在线段树上单点修改即可。每一次询问操作即为求最大的 \(w\),使得 \({\rm pos}_0, {\rm pos}_1, \cdots ,{\rm pos}_w\) 位于同一条简单链上。可以直接在线段树上二分。单次操作的时间复杂度均为 \(O(\log n)\)。
总时间复杂度为 \(O((n + q) \log n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
int n, q, tt, p[N], pos[N], depth[N], firstp[N], logv[N], rmq_d[N][20], rmq_p[N][20];
vector<int> graph[N];
pair<int, int> nodes[N << 2];
void dfs(int u, int father) {
++tt;
firstp[u] = tt;
rmq_p[tt][0] = u;
rmq_d[tt][0] = depth[u];
for (auto v : graph[u]) {
if (v != father) {
depth[v] = depth[u] + 1;
dfs(v, u);
++tt;
rmq_p[tt][0] = u;
rmq_d[tt][0] = depth[u];
}
}
}
void rmq_init() {
for (int i = 2; i <= tt; ++i) {
logv[i] = logv[i >> 1] + 1;
}
for (int j = 1; (1 << j) <= tt; ++j) {
for (int i = 1; i + (1 << j) - 1 <= tt; ++i) {
int dl = rmq_d[i][j - 1];
int dr = rmq_d[i + (1 << j - 1)][j - 1];
rmq_d[i][j] = min(dl, dr);
rmq_p[i][j] = dl < dr ? rmq_p[i][j - 1] : rmq_p[i + (1 << j - 1)][j - 1];
}
}
}
int getlca(int u, int v) {
u = firstp[u];
v = firstp[v];
if (u > v) {
swap(u, v);
}
int k = logv[v - u + 1];
return rmq_d[u][k] < rmq_d[v - (1 << k) + 1][k] ? rmq_p[u][k] : rmq_p[v - (1 << k) + 1][k];
}
#define lo (o<<1)
#define ro (o<<1|1)
bool including(int u, int v, int a, int b) {
int lca = getlca(u, v);
if ((getlca(a, u) != a && getlca(a, v) != a) || getlca(a, lca) != lca) {
return false;
}
if ((getlca(b, u) != b && getlca(b, v) != b) || getlca(b, lca) != lca) {
return false;
}
return true;
}
pair<int, int> operator + (const pair<int, int>& a, const pair<int, int>& b) {
if (!~a.first || !~b.first) {
return {-1, -1};
}
if (including(a.first, a.second, b.first, b.second)) {
return {a.first, a.second};
}
if (including(a.first, b.first, a.second, b.second)) {
return {a.first, b.first};
}
if (including(a.first, b.second, a.second, b.first)) {
return {a.first, b.second};
}
if (including(a.second, b.first, a.first, b.second)) {
return {a.second, b.first};
}
if (including(a.second, b.second, a.first, b.first)) {
return {a.second, b.second};
}
if (including(b.first, b.second, a.first, a.second)) {
return {b.first, b.second};
}
return {-1, -1};
}
void build(int l, int r, int o) {
if (l == r) {
nodes[o] = {pos[l], pos[l]};
} else {
int mid = l + r >> 1;
build(l, mid, lo);
build(mid + 1, r, ro);
nodes[o] = nodes[lo] + nodes[ro];
}
}
void modify(int l, int r, int o, int p) {
if (l == r) {
nodes[o] = {pos[l], pos[l]};
} else {
int mid = l + r >> 1;
if (p <= mid) {
modify(l, mid, lo, p);
} else {
modify(mid + 1, r, ro, p);
}
nodes[o] = nodes[lo] + nodes[ro];
}
}
int query(int l, int r, int o, pair<int, int> result) {
if (l == r) {
result = result + nodes[o];
return ~result.first ? l : l - 1;
} else {
int mid = l + r >> 1;
if (!~(result + nodes[lo]).first) {
return query(l, mid, lo, result);
} else {
return query(mid + 1, r, ro, result + nodes[lo]);
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &p[i]);
pos[p[i]] = i;
}
for (int i = 2; i <= n; ++i) {
int x;
scanf("%d", &x);
graph[i].push_back(x);
graph[x].push_back(i);
}
dfs(1, 0);
rmq_init();
build(0, n - 1, 1);
scanf("%d", &q);
while (q--) {
int type, i, j;
scanf("%d", &type);
if (type == 1) {
scanf("%d%d", &i, &j);
swap(p[i], p[j]);
swap(pos[p[i]], pos[p[j]]);
modify(0, n - 1, 1, p[i]);
modify(0, n - 1, 1, p[j]);
} else {
printf("%d\n", query(0, n - 1, 1, {pos[0], pos[0]}) + 1);
}
}
return 0;
}
D. The Fair Nut’s getting crazy
记 \({\rm pre}_i\) 为 \(a_i\) 在位置 \(i\) 之前最晚出现的位置(若不存在这样的位置,那么 \({\rm pre}_i = 0\)),\({\rm suf}_i\) 为 \(a_i\) 在位置 \(i\) 之后最早出现的位置(若不存在这样的位置,那么 \({\rm suf}_i = n + 1\))。
考虑枚举两个子段的交区间 \([i, j]\),记 \(l = \max_\limits{i \leq k \leq j}\{{\rm pre}_k\}, r = \min_\limits{i \leq k \leq j}\{{\rm suf}_k\}\),那么显然,右端点为 \(j\) 的子段的合法左端点在区间 \((l, i)\) 内,左端点为 \(i\) 的子段的合法右端点在区间 \((j, r)\) 内,因此两个子段的交区间为 \([i, j]\) 的合法方案数为 \((i - l - 1) \times (r - j - 1)\)。
式子 \((i - l - 1) \times (r - j - 1)\) 不好直接维护,考虑将其拆开,分别维护各项的值。我们顺次枚举所有右端点 \(j\),在这个过程中用线段树维护每个左端点对应的各项的值,那么对于每个右端点,我们只需要对合法的区间做一次区间统计即可。
总时间复杂度为 \(O(n \log n)\)。但由于我在每次移动右端点 \(j\) 时直接在原序列上二分来查找当前的 \({\rm pre}_j\) 与 \({\rm suf}_j\) 可更新的区间,因此下面代码的时间复杂度为 \(O(n \log^2 n)\)。反正过了不管了。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
void add(int& x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
}
void sub(int& x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
}
int mul(int x, int y) {
return (long long) x * y % mod;
}
int n, a[N], pre[N], suf[N], pos[N];
struct info_t {
int maxl, minr, tagl, tagr, suml, sumr, sumlr, sumir, sumcoef;
info_t() {
tagl = -1;
tagr = -1;
}
info_t(int maxl, int minr, int suml, int sumr, int sumlr, int sumir, int sumcoef): maxl(maxl), minr(minr), suml(suml), sumr(sumr), sumlr(sumlr), sumir(sumir), sumcoef(sumcoef) {}
info_t operator + (info_t a) {
info_t result;
result.maxl = max(maxl, a.maxl);
result.minr = min(minr, a.minr);
result.suml = (suml + a.suml) % mod;
result.sumr = (sumr + a.sumr) % mod;
result.sumlr = (sumlr + a.sumlr) % mod;
result.sumir = (sumir + a.sumir) % mod;
result.sumcoef = (sumcoef + a.sumcoef) % mod;
return result;
}
} info[N << 2];
#define lo (o<<1)
#define ro (o<<1|1)
int samediff_sum(int l, int r) {
return ((long long) (l + r) * (r - l + 1) >> 1) % mod;
}
void cover_l(int l, int r, int o, int prep) {
info[o].tagl = prep;
info[o].maxl = prep;
info[o].suml = mul(r - l + 1, prep);
info[o].sumlr = mul(info[o].sumr, prep);
info[o].sumcoef = (info[o].suml - samediff_sum(l - 1, r - 1) + mod) % mod;
}
void cover_r(int l, int r, int o, int sufp) {
info[o].tagr = sufp;
info[o].minr = sufp;
info[o].sumr = mul(r - l + 1, sufp);
info[o].sumlr = mul(info[o].suml, sufp);
info[o].sumir = mul(sufp, samediff_sum(l, r));
}
void push_down(int l, int r, int o) {
int mid = l + r >> 1;
if (~info[o].tagl) {
cover_l(l, mid, lo, info[o].tagl);
cover_l(mid + 1, r, ro, info[o].tagl);
info[o].tagl = -1;
}
if (~info[o].tagr) {
cover_r(l, mid, lo, info[o].tagr);
cover_r(mid + 1, r, ro, info[o].tagr);
info[o].tagr = -1;
}
}
void modify(int l, int r, int o, int p, int prep, int sufp) {
if (l == r) {
info[o] = info_t(prep, sufp, prep, sufp, mul(prep, sufp), mul(l, sufp), (prep - l + 1 + mod) % mod);
} else {
int mid = l + r >> 1;
push_down(l, r, o);
if (p <= mid) {
modify(l, mid, lo, p, prep, sufp);
} else {
modify(mid + 1, r, ro, p, prep, sufp);
}
info[o] = info[lo] + info[ro];
}
}
void modify_max(int l, int r, int o, int ql, int qr, int prep) {
if (ql <= l && r <= qr) {
cover_l(l, r, o, prep);
} else {
int mid = l + r >> 1;
push_down(l, r, o);
if (ql <= mid) {
modify_max(l, mid, lo, ql, qr, prep);
} if (qr > mid) {
modify_max(mid + 1, r, ro, ql, qr, prep);
}
info[o] = info[lo] + info[ro];
}
}
void modify_min(int l, int r, int o, int ql, int qr, int sufp) {
if (ql <= l && r <= qr) {
cover_r(l, r, o, sufp);
} else {
int mid = l + r >> 1;
push_down(l, r, o);
if (ql <= mid) {
modify_min(l, mid, lo, ql, qr, sufp);
} if (qr > mid) {
modify_min(mid + 1, r, ro, ql, qr, sufp);
}
info[o] = info[lo] + info[ro];
}
}
info_t query(int l, int r, int o, int ql, int qr) {
if (ql <= l && r <= qr) {
return info[o];
} else {
int mid = l + r >> 1;
push_down(l, r, o);
if (qr <= mid) {
return query(l, mid, lo, ql, qr);
} else if (ql > mid) {
return query(mid + 1, r, ro, ql, qr);
} else {
return query(l, mid, lo, ql, qr) + query(mid + 1, r, ro, ql, qr);
}
}
}
int main() {
scanf("%d", &n);
vector<int> h;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
h.push_back(a[i]);
}
sort(h.begin(), h.end());
h.erase(unique(h.begin(), h.end()), h.end());
for (int i = 1; i <= n; ++i) {
a[i] = lower_bound(h.begin(), h.end(), a[i]) - h.begin();
}
for (int i = 1; i <= n; ++i) {
pre[i] = pos[a[i]] ? pos[a[i]] : 0;
pos[a[i]] = i;
}
memset(pos, 0, sizeof pos);
for (int i = n; i; --i) {
suf[i] = pos[a[i]] ? pos[a[i]] : n + 1;
pos[a[i]] = i;
}
int answer = 0;
for (int i = 1, j = 1; i <= n; ++i) {
for (; j <= pre[i]; ++j);
int l = j, r = i;
while (l != r) {
int mid = l + r >> 1;
if (query(1, n, 1, mid, i - 1).maxl < pre[i]) {
r = mid;
} else {
l = mid + 1;
}
}
if (l <= i - 1) {
modify_max(1, n, 1, l, i - 1, pre[i]);
}
l = j, r = i;
while (l != r) {
int mid = l + r >> 1;
if (query(1, n, 1, mid, i - 1).minr > suf[i]) {
r = mid;
} else {
l = mid + 1;
}
}
if (l <= i - 1) {
modify_min(1, n, 1, l, i - 1, suf[i]);
}
modify(1, n, 1, i, pre[i], suf[i]);
info_t result = query(1, n, 1, j, i);
add(answer, result.sumir);
sub(answer, result.sumlr);
add(answer, mul(i + 1, result.sumcoef));
sub(answer, result.sumr);
}
printf("%d\n", answer);
return 0;
}
E. The Fair Nut and Rectangles
斜率优化裸题。
将所有矩形按 \(x\) 排序之后,定义 \(f_i\) 表示最后一个选择的矩形为 \(i\) 的最大收益。转移即为 \(f_i = \max_\limits{j < i} \{f_j + y_i \times (x_i - x_j)\} - a_i\),即 \(f_i = \max_\limits{j < i}\{f_j - y_ix_j\} + x_iy_i - a_i\),将 \(y_i\) 看做斜率,\((x_i, f_i)\) 视为转移点,那么维护所有转移点构成的上凸包即可。由于斜率是单调下降的,因此可以直接用单调队列维护。时间复杂度为 \(O(n)\)。
这绝对是这套题里面最简单的一道题。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
struct matrix {
int x, y;
long long v;
} a[N];
int n, convex_hull[N];
long long f[N];
double slope(int i, int j) {
return (double) (f[i] - f[j]) / (a[i].x - a[j].x);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d%lld", &a[i].x, &a[i].y, &a[i].v);
}
sort(a + 1, a + 1 + n, [&] (const matrix& a, const matrix& b) {
return a.x < b.x;
});
int ql = 0, qr = 0;
long long answer = 0;
for (int i = 1; i <= n; ++i) {
for (; ql < qr && slope(convex_hull[ql], convex_hull[ql + 1]) >= a[i].y; ++ql);
int j = convex_hull[ql];
f[i] = f[j] + (long long) a[i].y * (a[i].x - a[j].x) - a[i].v;
answer = max(answer, f[i]);
for (; ql < qr && slope(convex_hull[qr], i) >= slope(convex_hull[qr - 1], i); --qr);
convex_hull[++qr] = i;
}
printf("%lld\n", answer);
return 0;
}
F. The Fair Nut and Amusing Xor
和 LOJ6500. 「雅礼集训 2018 Day2」操作 的主要思路类似的一个题。
考虑先将序列 \(a, b\) 差分,令 \(a'_i = a_i\ {\rm xor}\ a_{i - 1}, b'_i = b_i\ {\rm xor}\ b_{i - 1}\),新建序列 \(c\),满足 \(c_i = a'_i\ {\rm xor}\ b'_i\),那么每一次操作会使得序列 \(c\) 中两个下标差为 \(k\) 的元素异或上一个相同的值,我们的目的是利用最小的操作次数使得序列 \(c\) 的所有元素变为 \(0\)。
由于模 \(k\) 后值不相同的位置不会互相影响,因此我们将序列 \(c\) 的所有元素按照下标模 \(k\) 的值分组,下标模 \(k\) 的值相同的元素位于同一组。对于每一组,我们考虑从左至右依次将每一个不为 \(0\) 的元素消掉的过程,不难发现,该组的所有元素最终能为 \(0\),当且仅当所有元素的异或和为 \(0\)。同时,在保证能够使该组的所有元素最终为 \(0\) 的前提下,如果该组内有 \(x\) 个元素,那么我们需要的最小操作次数为 \(x - w\),其中 \(w\) 为该组内元素的前缀异或和为 \(0\) 的前缀数量,因为显然每存在一个前缀异或和为 \(0\) 的前缀,我们都可以省掉一步操作。
由于对于每次修改操作,最多只会修改序列 \(c\) 中的两个元素。在修改序列 \(c\) 中的一个元素后,我们需要重新维护对应组内的信息。因此,我们需要解决的根本问题是在修改完单个元素后快速求出对应组内有多少个前缀异或和为 \(0\) 的前缀。当 \(k > \sqrt n\) 时,每一组的元素较少,我们可以直接暴力维护;当 \(k \leq \sqrt n\) 时,我们可以对每组分块,由于序列的值域较小,因此我们可以直接开数组记录每个块内前缀异或和为某个值的前缀数量,修改时直接在块内暴力修改,之后再顺次扫一遍所有块更新答案即可。
时间复杂度为 \(O((n + q) \sqrt n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, block = 400;
int n, k, q, a[N], b[N], c[N], endv[N], result[N], id[N], pos[N], num[N], total, answer;
vector<vector<int>> team[500];
vector<int> team_v[500];
void init(bool common) {
if (common) {
for (int i = 0; i < k; ++i) {
int value = 0;
for (int j = !i ? k : i; j <= n; j += k) {
value ^= c[j];
if (value) {
++result[i];
}
if (j + k > n) {
endv[i] = !value;
}
}
answer += result[i];
total += endv[i];
}
} else {
for (int i = 0; i < n; ++i) {
id[i] = i / block;
}
for (int i = 0; i < k; ++i) {
int t = 0;
for (int j = !i ? k : i; j <= n; j += k) {
pos[j] = t++;
}
num[i] = t;
vector<int> empty_vec(1 << 14, 0);
for (int j = 0; j <= id[t - 1]; ++j) {
team[i].push_back(empty_vec);
}
team_v[i].resize(team[i].size());
int value = 0;
for (int j = !i ? k : i; j <= n; j += k) {
value ^= c[j];
++team[i][id[pos[j]]][value];
if (j + k > n || id[pos[j]] != id[pos[j + k]]) {
team_v[i][id[pos[j]]] = value;
value = 0;
}
}
result[i] = num[i];
for (int j = 0; j < team[i].size(); ++j) {
result[i] -= team[i][j][value];
value ^= team_v[i][j];
}
endv[i] = !value;
answer += result[i];
total += endv[i];
}
}
}
void modify(bool common, int i, int p) {
total -= endv[i];
answer -= result[i];
if (common) {
result[i] = 0;
int value = 0;
for (int j = !i ? k : i; j <= n; j += k) {
value ^= c[j];
if (value) {
++result[i];
}
if (j + k > n) {
endv[i] = !value;
}
}
} else {
result[i] = num[i];
int ind = id[pos[p]];
fill(team[i][ind].begin(), team[i][ind].end(), 0);
int l = p, r = p;
for (; l > 0 && id[pos[l]] == ind; l -= k);
for (; r <= n && id[pos[r]] == ind; r += k);
l += k;
r -= k;
int value = 0;
for (int j = l; j <= r; j += k) {
value ^= c[j];
++team[i][ind][value];
}
team_v[i][ind] = value;
value = 0;
for (int j = 0; j < team[i].size(); ++j) {
result[i] -= team[i][j][value];
value ^= team_v[i][j];
}
endv[i] = !value;
}
answer += result[i];
total += endv[i];
}
int main() {
scanf("%d%d%d", &n, &k, &q);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &b[i]);
}
++n;
for (int i = 1; i <= n; ++i) {
c[i] = a[i] ^ a[i - 1] ^ b[i] ^ b[i - 1];
}
init(k > block);
printf("%d\n", total == k ? answer : -1);
while (q--) {
char type[2];
int p, v;
scanf("%s%d%d", type, &p, &v);
if (*type == 'a') {
a[p] = v;
} else {
b[p] = v;
}
c[p] = a[p] ^ a[p - 1] ^ b[p] ^ b[p - 1];
++p;
c[p] = a[p] ^ a[p - 1] ^ b[p] ^ b[p - 1];
--p;
modify(k > block, p % k, p);
++p;
modify(k > block, p % k, p);
printf("%d\n", total == k ? answer : -1);
}
return 0;
}
CF1083(Round #526 Div. 1) 简要题解的更多相关文章
- Codeforces Round #557 (Div. 1) 简要题解
Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...
- Codeforces Round #545 (Div. 1) 简要题解
这里没有翻译 Codeforces Round #545 (Div. 1) T1 对于每行每列分别离散化,求出大于这个位置的数字的个数即可. # include <bits/stdc++.h&g ...
- Codeforces Round #483 (Div. 1) 简要题解
来自FallDream的博客,未经允许,请勿转载,谢谢. 为了证明一下我又来更新了,写一篇简要的题解吧. 这场比赛好像有点神奇,E题莫名是道原题,导致有很多选手直接过掉了(Claris 表演24s过题 ...
- Codeforces Round #535(div 3) 简要题解
Problem A. Two distinct points [题解] 显然 , 当l1不等于r2时 , (l1 , r2)是一组解 否则 , (l1 , l2)是一组合法的解 时间复杂度 : O(1 ...
- Codeforces Round #498 (Div. 3) 简要题解
[比赛链接] https://codeforces.com/contest/1006 [题解] Problem A. Adjacent Replacements [算法] 将序列中的所有 ...
- [题解][Codeforces]Codeforces Round #602 (Div. 1) 简要题解
orz djq_cpp lgm A 题意 给定一个分别含有 \(\frac n2\) 个左括号和右括号的括号序列 每次可以将序列的一个区间翻转 求一个不超过 \(n\) 次的操作方案,使得操作完之后的 ...
- Codeforces Round #398 (div.2)简要题解
这场cf时间特别好,周六下午,于是就打了打(谁叫我永远1800上不去div1) 比以前div2的题目更均衡了,没有太简单和太难的...好像B题难度高了很多,然后卡了很多人. 然后我最后做了四题,E题感 ...
- Codeforces Round #588 (Div. 1) 简要题解
1. 1229A Marcin and Training Camp 大意: 给定$n$个对$(a_i,b_i)$, 要求选出一个集合, 使得不存在一个元素好于集合中其他所有元素. 若$a_i$的二进制 ...
- Codeforces Round #576 (Div. 1) 简要题解 (CDEF)
1198 C Matching vs Independent Set 大意: 给定$3n$个点的无向图, 求构造$n$条边的匹配, 或$n$个点的独立集. 假设已经构造出$x$条边的匹配, 那么剩余$ ...
- # Codeforces Round #529(Div.3)个人题解
Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...
随机推荐
- qt QTcpServer与QTcpSocket通讯
分类: C/C++ TCP TCP是一个基于流的协议.对于应用程序,数据表现为一个长长的流,而不是一个大大的平面文件.基于TCP的高层协议通常是基于行的或者基于块的. ...
- setitemdata 32位 or 64位
我用SetItemData 和GetItemData把数据库一条数据导入到CListctrl 32位下 程序都可以跑 GetItemData能得到自定义类数据 可以64位得不到?
- 使用WindowsFormsApplicationBase实现引导界面
1.需要添加对Microsoft.VisualBasic 引用, 2.准备frmMain,frmSplash两个窗口 说明: frmSplash在主线程上建立,但是在独立线程上进行消息循 ...
- jquery对属性和特性的操作
attribute(特性)和property(属性)是两个不同的概念.attribute表示HTML文档节点的特性,property表示DOM元素的属性 这些属性例如selectedIndex, ta ...
- redis windows下安装
1.下载redis windows文件包 下载地址 2.解压文件包 复制压缩包地址 3.进入cmd 命令行 cd进入redis文件包目录 4.执行 redis-server.exe 使用netsta ...
- Hadoop学习【一】单机版搭建
首先要说一下,Hadoop 2.x版本以后的改动,在这里帖一篇文章,觉得写的不错. http://www.ibm.com/developerworks/cn/opensource/os-cn-hado ...
- webapi Model Validation 模型验证
通常情况下,对于那些经常为别人提供数据接口的开发人员来说,对于调用方传递过来的参数都会有验证处理.例如: if (string.IsNullOrEmpty(entity.Name)) { //当姓名为 ...
- ZOJ1586 QS Network 2017-04-13 11:46 39人阅读 评论(0) 收藏
QS Network Time Limit: 2 Seconds Memory Limit: 65536 KB Sunny Cup 2003 - Preliminary Round Apri ...
- 基于jCOM搭建Java-微软信息桥梁(下)
第一部分析了BEA提供的Java/COM互操作解决方案—jCOM的实现原理:本文是第二部分,比较全面地分析了Weblogic Server的jCOM实现技术之后,通过一个具体实例来说明了jCOM的具体 ...
- vs2015上使用github进行版本控制
我是用的是vs2015企业版 一.首先创建项目,右下角选择新建git存储库 二.在工具栏选择团队-管理连接,打开团队资源管理器,点击同步 . 三.选择下面的发布选项 四.在gitgub上新建仓库,得到 ...