这里没有翻译

Codeforces Round #545 (Div. 1)

T1

对于每行每列分别离散化,求出大于这个位置的数字的个数即可。

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(1005); int n, m, a[maxn][maxn], mx1[maxn][maxn], mx2[maxn][maxn], q[maxn], len; int main() {
int i, j, p;
scanf("%d%d", &n, &m);
for (i = 1; i <= n; ++i)
for (j = 1; j <= m; ++j) scanf("%d", &a[i][j]);
for (i = 1; i <= n; ++i) {
for (j = 1; j <= m; ++j) q[j] = a[i][j];
sort(q + 1, q + m + 1), len = unique(q + 1, q + m + 1) - q - 1;
for (j = 1; j <= m; ++j) {
p = lower_bound(q + 1, q + len + 1, a[i][j]) - q;
mx1[i][j] = p, mx2[i][j] = len - p;
}
}
for (i = 1; i <= m; ++i) {
for (j = 1; j <= n; ++j) q[j] = a[j][i];
sort(q + 1, q + n + 1), len = unique(q + 1, q + n + 1) - q - 1;
for (j = 1; j <= n; ++j) {
p = lower_bound(q + 1, q + len + 1, a[j][i]) - q;
mx1[j][i] = max(p, mx1[j][i]), mx2[j][i] = max(len - p, mx2[j][i]);
}
}
for (i = 1; i <= n; ++i, puts(""))
for (j = 1; j <= m; ++j) printf("%d ", mx1[i][j] + mx2[i][j]);
return 0;
}

T2

每次选择当前串的最长的 \(border\) 接上去即可

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(5e5 + 5); int len1, len2, nxt[maxn], cnt0, cnt, cnt1, mx;
char s[maxn], t[maxn], ans[maxn]; int main() {
int i, j, len = 0;
scanf(" %s %s", s + 1, t + 1);
len1 = strlen(s + 1), len2 = strlen(t + 1);
for (i = 1; i <= len1; ++i) cnt0 += s[i] == '0';
for (i = 1; i <= len2; ++i) cnt += t[i] == '0';
if (len1 < len2 || cnt0 < cnt || len1 - cnt0 < len2 - cnt) return printf("%s\n", s + 1), 0;
for (i = 2, j = 0; i <= len2; ++i) {
while (j && t[j + 1] != t[i]) j = nxt[j];
if (t[j + 1] == t[i]) ++j;
nxt[i] = j;
}
for (i = 1; i <= len2; ++i) ans[i] = t[i];
len = len2, cnt1 = len1 - cnt0, cnt0 -= cnt, mx = nxt[len2], cnt1 -= len2 - cnt;
while (cnt0 && cnt1) {
for (i = mx + 1; i <= len2 && cnt1 && cnt0; ++i)
if (cnt0 - (t[i] == '0') >= 0 && cnt1 - (t[i] == '1') >= 0)
ans[++len] = t[i], cnt0 -= t[i] == '0', cnt1 -= t[i] == '1';
}
while (cnt0) ans[++len] = '0', --cnt0;
while (cnt1) ans[++len] = '1', --cnt1;
for (i = 1; i <= len1; ++i) putchar(ans[i]);
return puts(""), 0;
}

T3

拆点,对于一个点 \(x\),拆成 \((x,1),(x,2),...,(x,d)\),在原图中如果有边 \(x,y\) 则连边 \((x,i),(y,i\%d+1)\)。

可以发现如果 \((x,i)\) 能到 \((x,j)\),那么 \((x,j)\) 也一定能到达 \((x,i)\)。

所以 \((x,i),(x,j)\) 要么在同一个强连通分量里,要么不在同一条直链上。

所以直接缩点 \(DP\) 即可。

// Memory limit exceeded on test 73
# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(5e6 + 5); struct Edge { int to, next; }; int first[maxn], cnt, n, m, dd, id[100005][55], www[maxn], bf[maxn], val[maxn], num, ans;
int dfn[maxn], low[maxn], idx, st[maxn], us[maxn], tot, tp, bel[maxn], f[maxn], d[maxn];
Edge edge[maxn];
char s[55];
vector <int> dag[maxn];
queue <int> Q;
bitset <maxn> vis; inline void Add(int u, int v) {
edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
} void Tarjan(int u) {
int e, v, r;
dfn[u] = low[u] = ++idx, vis[u] = 1, st[++tp] = u;
for (e = first[u]; ~e; e = edge[e].next)
if (!dfn[v = edge[e].to]) Tarjan(v), low[u] = min(low[u], low[v]);
else if (vis[v]) low[u] = min(low[u], dfn[v]);
if (low[u] == dfn[u]) {
++num;
do {
vis[v = st[tp--]] = 0;
if (www[v] && us[bf[v]] != num) us[bf[v]] = num, ++val[num];
bel[v] = num;
} while (v ^ u);
}
} int main() {
int i, j, u, v, e;
memset(first, -1, sizeof(first));
scanf("%d%d%d", &n, &m, &dd);
for (i = 1; i <= n; ++i)
for (j = 1; j <= dd; ++j) id[i][j] = ++tot, bf[tot] = i;
for (i = 1; i <= m; ++i) {
scanf("%d%d", &u, &v);
for (j = 1; j <= dd; ++j) Add(id[u][j], id[v][j % dd + 1]);
}
for (i = 1; i <= n; ++i) {
scanf(" %s", s + 1);
for (j = 1; j <= dd; ++j) www[id[i][j]] = s[j] == '1';
}
for (i = 1; i <= tot; ++i) if (!dfn[i]) Tarjan(i);
for (i = 1; i <= tot; ++i)
for (e = first[i]; ~e; e = edge[e].next)
if (bel[i] != bel[edge[e].to]) dag[bel[i]].push_back(bel[edge[e].to]), ++d[bel[edge[e].to]];
memset(f, -63, sizeof(f)), f[bel[1]] = val[bel[1]];
for (i = 1; i <= num; ++i) if (!d[i]) Q.push(i);
while (!Q.empty()) {
u = Q.front(), Q.pop(), ans = max(ans, f[u]);
for (int t : dag[u]) {
f[t] = max(f[t], f[u] + val[t]);
if (!--d[t]) Q.push(t);
}
}
printf("%d\n", ans);
return 0;
}

T4

\(floyed\) 判环法,一个人 \(a\) 一次 \(1\) 步,另一个人 \(b\) 一次 \(2\) 步。

设 \(a\) 走了 \(t+v\) 步,\(b\) 走了 \(2t+2v\) 步。

不难发现 \(c|(t+v)\),而 \(a\) 是一次 \(1\) 步,所以 \(a\) 一定没有走完一个环,所以只要再次走 \(t\) 步就可以刚好到了终点。

其它的点也是一样。

总步骤 \(\le 3(c+t)\)。

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; char s[233]; inline int Read() {
int x, i;
scanf("%d", &x);
for (i = 1; i <= x; ++i) scanf(" %s", s);
return x;
} int main() {
while (true) {
printf("next 0\n"), fflush(stdout), Read();
printf("next 0 1\n"), fflush(stdout);
if (Read() == 2) break;
}
while (true) {
printf("next 0 1 2 3 4 5 6 7 8 9\n"), fflush(stdout);
if (Read() == 1) break;
}
printf("done"), fflush(stdout);
return 0;
}

T5

不难发现每次加的一些 \(0\) 只要保留第一个就行了。

一操作很好做,直接扔掉前面的信息即可。

考虑二三操作,可以想到用单调队列来维护。

假设 \(x<y\),那么一次三操作 \(v_x\) 变得小于 \(v_y\) 的条件显然是

\(\frac{v_x-v_y}{x-y}>-s\),所以维护一个 \((v_x,x)\) 的斜率单调递增的下凸壳即可。

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(3e5 + 5); int n, m;
ll Q[maxn], val[maxn], mov, hd, tl, ed, tagb, tags; inline ll Calc(int x) { return val[x] + tagb + tags * (Q[x] + mov - 1); } int main() {
ll op, k, b, s;
scanf("%d%d", &n, &m);
Q[hd = tl = val[0] = 0] = 1, ed = n;
while (m--) {
scanf("%lld", &op);
if (op <= 2) scanf("%lld", &k);
else scanf("%lld%lld", &b, &s);
if (op == 1) mov += k, ed += k, Q[hd = tl = 0] = 1 - mov, val[hd] = tagb = tags = 0;
else if (op == 2) {
while (hd < tl && 1.0 * (Calc(tl) - Calc(tl - 1)) / (Q[tl] - Q[tl - 1]) >= -1.0 * Calc(tl) / (ed + 1 - Q[tl] - mov)) --tl;
Q[++tl] = ed + 1 - mov, val[tl] = -tagb - tags * ed, ed += k;
}
else tagb += b, tags += s;
while (hd < tl && val[tl] + tags * (Q[tl] - Q[tl - 1]) - val[tl - 1] >= 0) --tl;
printf("%lld %lld\n", Q[tl] + mov, Calc(tl));
}
return 0;
}

T6

首先可以以最后烧掉的点为根,变成有根树。

考虑一次 \(up~u\) 操作的影响,设原来的根为 \(rt\),那么会使得 \((u,rt)\) 这条链的顺序变成 \(rt\) 烧到 \(u\) 并且是最后烧的链,其它点相对顺序不变。

现在问题是怎么统计每个点在它之前的点的个数。

可以把 \(up\) 操作看成是一种区间(链)覆盖一个新的最大编号,然后换根。

那么一个点的排名就变成了小于等于它的编号的点个数减去它祖先编号和它相同的点的个数。

这种染色问题可以用 \(LCT\) 维护,\(up\) 就直接 \(access+makeroot\),同一个编号的点一定在一棵 \(Splay\) 中,直接覆盖即可。

外加一个树状数组维护小于等于它的编号的点个数。

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(4e5 + 5); int n, q, mx, cnt_col, d[maxn], cnt[maxn];
vector <int> edge[maxn];
int fa[maxn], ch[2][maxn], rev[maxn], col[maxn], sta[maxn], tp, size[maxn];
priority_queue <int> Q; inline void AddEdge(int u, int v) { edge[u].push_back(v), edge[v].push_back(u), ++d[u], ++d[v]; } inline void Add(int x, int v) { for (; x <= mx; x += x & -x) cnt[x] += v; } inline int Query(int x) {
int ret = 0;
for (; x; x ^= x & -x) ret += cnt[x];
return ret;
} inline int Isroot(int x) { return (ch[0][fa[x]] ^ x) && (ch[1][fa[x]] ^ x); } inline int Son(int x) { return ch[1][fa[x]] == x; } inline void Update(int x) { size[x] = size[ch[0][x]] + size[ch[1][x]] + 1; } inline void Reverse(int x) { if (x) swap(ch[0][x], ch[1][x]), rev[x] ^= 1; } inline void Cover(int x, int v) { if (x) col[x] = v; } inline void Pushdown(int x) {
if (rev[x]) rev[x] ^= 1, Reverse(ch[0][x]), Reverse(ch[1][x]);
Cover(ch[0][x], col[x]), Cover(ch[1][x], col[x]);
} inline void Rotate(int x) {
int y = fa[x], z = fa[y], c = Son(x);
if (!Isroot(y)) ch[Son(y)][z] = x;
fa[x] = z, ch[c][y] = ch[c ^ 1][x], fa[ch[c][y]] = y;
ch[c ^ 1][x] = y, fa[y] = x, Update(y);
} inline void Splay(int x) {
int y;
sta[tp = 1] = x;
for (y = x; !Isroot(y); y = fa[y]) sta[++tp] = fa[y];
while (tp) Pushdown(sta[tp--]);
for (y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
if (!Isroot(y)) (Son(x) ^ Son(y)) ? Rotate(x) : Rotate(y);
Update(x);
} inline void Access(int x) {
int y;
for (y = 0; x; y = x, x = fa[x]) {
Splay(x), Add(col[x], -size[ch[0][x]] - 1);
ch[1][x] = y, Update(x);
}
} inline void Makeroot(int x) {
Access(x), Splay(x), Reverse(x), Cover(x, ++cnt_col), Add(col[x], size[x]);
} inline int When(int x) { return Splay(x), Query(col[x]) - size[ch[0][x]]; } int main() {
int i, u, v;
char op[233];
scanf("%d%d", &n, &q), mx = n + q;
for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u, v);
for (i = 1; i <= n; ++i) if (d[i] == 1) Q.push(-i);
while (!Q.empty()) {
u = -Q.top(), Q.pop(), --d[u], Add(col[u] = ++cnt_col, 1);
for (int to : edge[u]) if (--d[to] == 1) Q.push(-to);
}
for (u = 1; u <= n; ++u)
for (int to : edge[u]) if (col[u] > col[to]) fa[to] = u;
while (q--) {
scanf(" %s%d", op + 1, &u);
if (op[1] == 'u') Makeroot(u);
else if (op[1] == 'w') printf("%d\n", When(u));
else scanf("%d", &v), printf("%d\n", When(u) < When(v) ? u : v);
}
return 0;
}

Codeforces Round #545 (Div. 1) 简要题解的更多相关文章

  1. Codeforces Round #557 (Div. 1) 简要题解

    Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...

  2. Codeforces Round #483 (Div. 1) 简要题解

    来自FallDream的博客,未经允许,请勿转载,谢谢. 为了证明一下我又来更新了,写一篇简要的题解吧. 这场比赛好像有点神奇,E题莫名是道原题,导致有很多选手直接过掉了(Claris 表演24s过题 ...

  3. Codeforces Round #498 (Div. 3) 简要题解

    [比赛链接] https://codeforces.com/contest/1006 [题解] Problem A. Adjacent Replacements        [算法] 将序列中的所有 ...

  4. Codeforces Round #535(div 3) 简要题解

    Problem A. Two distinct points [题解] 显然 , 当l1不等于r2时 , (l1 , r2)是一组解 否则 , (l1 , l2)是一组合法的解 时间复杂度 : O(1 ...

  5. [题解][Codeforces]Codeforces Round #602 (Div. 1) 简要题解

    orz djq_cpp lgm A 题意 给定一个分别含有 \(\frac n2\) 个左括号和右括号的括号序列 每次可以将序列的一个区间翻转 求一个不超过 \(n\) 次的操作方案,使得操作完之后的 ...

  6. Codeforces Round #398 (div.2)简要题解

    这场cf时间特别好,周六下午,于是就打了打(谁叫我永远1800上不去div1) 比以前div2的题目更均衡了,没有太简单和太难的...好像B题难度高了很多,然后卡了很多人. 然后我最后做了四题,E题感 ...

  7. Codeforces Round #588 (Div. 1) 简要题解

    1. 1229A Marcin and Training Camp 大意: 给定$n$个对$(a_i,b_i)$, 要求选出一个集合, 使得不存在一个元素好于集合中其他所有元素. 若$a_i$的二进制 ...

  8. Codeforces Round #576 (Div. 1) 简要题解 (CDEF)

    1198 C Matching vs Independent Set 大意: 给定$3n$个点的无向图, 求构造$n$条边的匹配, 或$n$个点的独立集. 假设已经构造出$x$条边的匹配, 那么剩余$ ...

  9. Codeforces Round #539&#542&#543&#545 (Div. 1) 简要题解

    Codeforces Round #539 (Div. 1) A. Sasha and a Bit of Relax description 给一个序列\(a_i\),求有多少长度为偶数的区间\([l ...

随机推荐

  1. ICMP与ping:投石问路的侦察兵

    1. ICMP 协议 ICMP全称Internet Control Message Protocol,就是互联网控制报文协议.ping命令就是基于它工作的. ICMP 报文是封装在 IP 包 里面的. ...

  2. IO、NIO、AIO

    一. IO 传统的IO是同步阻塞模式,数据的读取与写入会阻塞在一个线程内等待其完成. 主要面向字节流编程.(流是单向的) 二. NIO NIO支持同步非阻塞模式,在进行IO调用后,然后去 轮询调用结果 ...

  3. Yarn 资源调度框架

    Yarn 资源调度框架    实现对资源的细粒度封装(cpu,内存,带宽)    此外,还可以通过yarn协调多种不同计算框架(MR,Spark)    概述        Apache Hadoop ...

  4. javascript数据结构与算法---检索算法(顺序查找、最大最小值、自组织查询)

    javascript数据结构与算法---检索算法(顺序查找.最大最小值.自组织查询) 一.顺序查找法 /* * 顺序查找法 * * 顺序查找法只要从列表的第一个元素开始循环,然后逐个与要查找的数据进行 ...

  5. PEP_2007相关问题记录

    1.在C++中,int main(int argc, char** argv)中的参数是什么意思? 其中,第一个argc是输入的参数的个数,第二个argv可以理解为一个数组,我们可以通过argv来打印 ...

  6. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(三):搭建开发环境

    生成项目模板 登录Spring Initializr生成Spring Boot项目模板,保存到本地. 地址:https://start.spring.io/ 导入Maven项目 使用IDE导入生成的M ...

  7. Nginx限制访问次数和并发数

    Nginx限制访问速率和最大并发连接数模块--limit (防止DDOS攻击) http: ##zone=one或allips 表示设置名为"one"或"allips&q ...

  8. Linux进程间的通信

    一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟 ...

  9. 搭建laravel到nginx

    一.laravel的安装 搭建的第一步当然是安装好laravel,这里推介composer安装,由于国内的问题,极其推介使用国内的镜像去搭建,我在终端里本已经设置好常规的https和http之类的FQ ...

  10. Java RMI 框架(远程方法调用)

    转自:http://haolloyin.blog.51cto.com/1177454/332426 RMI(即Remote Method Invoke 远程方法调用).在Java中,只要一个类exte ...