「ZHYOI」Round 1比赛总结
第一次打洛谷比赛,还是大佬们出题,打的还不错。
比赛过程
A 题很显然是 \(O(n)\) 的,本来想打一个暴力,但是发现不会打,于是直接去想正解了,想了一会儿就出来了。
B 题很显然是找规律,先打了一个暴力,然后发现一些规律,写一写就出来了,然后一些小细节调了一会儿,然后就过了。
这是过去了 1 个小时感觉打的挺好,就满怀希望的看了一下第三题,然后就自闭了,想了一下发现不会,暴力也没啥思路,决定跳过。
第四题更没思路,不过惊讶的发现输出 1 有 10 分!!
在某位大佬的推荐下,决定去写第五题,写了 200 行的树剖+线段树+广搜,然后发现只有 30 分 ? 发现是没开 long long ,改了后就是 50 分了, 后面都超时了,这题看意思是过不了了, 就没搞了。
回头看第三题,想到一个 40 分的广搜,写了一会儿后发现竟然写对了,就拿了 40 分。
然后就开始摆烂到比赛结束。
最终排名:\(\text{rk41}\)
最终得分:\(\text{300pts}\)
远远超出预期。
题目总结
「ZHYOI-1」交作业
题目链接:「ZHYOI-1」交作业
这题其实很简单,我们只要找到第一个交不上作业的人,后面的都交不上。一个人如果想要叫上作业,那么在他交作业的时间段之前的作业没登记完,而登记的速度是每个时间一个,所以直接判断即可。
时间复杂度:\(O(n)\)
code
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
register long long x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
inline void write(int x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n;
long long p, p2;
int main() {
n = read();
bool f = false;
for (int i = 1; i <= n; i++) {
p = read();
if (p - (i - 1) > 0 && p != p2) {
write(n - i + 1);
f = true;
break;
}
p2 = p;
}
if (!f)
putchar('0');
return 0;
}
「ZHYOI-1」组合环
题目链接:「ZHYOI-1」组合环
这题其实不难,先输出 \(1-n\) , 然后在算出每个数剩下的出现次数,先考虑 \(n-1\) ,他只能和 \(n-2\) 相邻,所以直接输出 \({n \choose n-1}-1\) 对 \(n-1\) 和 \(n-2\) 即可,以此类推。
时间复杂度:\(O(2^n)\)
code
#include <bits/stdc++.h>
using namespace std;
inline int read() {
register int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
inline void write(int x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int rec[30][30] = {{0}};
long long C(int n, int m) {
if (rec[n][m] != 0)
return rec[n][m];
if (n == m || m == 0)return rec[n][m] = 1;
return rec[n][m] = C(n - 1, m - 1) + C(n - 1, m);
}
int n;
int cnt[30] = {0};
int main() {
n = read();
for (int i = 1; i <= n; i++)
write(i), putchar(' ');
for (int i = 1; i <= n; i++)
cnt[i] = C(n, i) - 1;
for (int i = n - 1; i >= 1; i--) {
for (int j = 1; j <= cnt[i]; j++)
if (i % 2 == n % 2)
write(i - 1), putchar(' '), write(i), putchar(' ');
else
write(i), putchar(' '), write(i - 1), putchar(' ');
cnt[i - 1] -= cnt[i];
}
if (n % 2 == 1)
putchar('0');
return 0;
}
「ZHYOI-1」石头
题目链接:「ZHYOI-1」石头
这题我不会正解,但是会暴力。对于 \(n,m \le 4\) 的情况,我们可以暴力广搜,搞一个结构体记录操作和当前数组,当数组只有一个数不为 0 时即可结束,当然,这只能得 \(40\) 分。
时间复杂度: \(\text{I don't know}\)
code
#include <bits/stdc++.h>
using namespace std;
int n, m;
int a[100005] = {0};
struct Node {
vector<pair<int, int> > op;
vector<int> array;
Node () {
vector<pair<int, int> >().swap(op);
vector<int>().swap(array);
}
bool chk() {
int cnt = 0;
for (int i = 0; i < (int)array.size(); i++)
if (array[i] == 0)
cnt++;
return cnt == (int)array.size() - 1;
}
void out() {
printf("%d\n", op.size());
for (int i = 0; i < (int)op.size(); i++)
printf("%d %d\n", op[i].first, op[i].second);
}
} tmp;
void bfs() {
queue<Node> q;
for (int i = 1; i <= m; i++)
tmp.array.push_back(a[i]);
q.push(tmp);
while (!q.empty()) {
Node h = q.front();
q.pop();
if (h.chk()) {
h.out();
break;
}
for (int i = 0; i < (int)h.array.size(); i++)
for (int j = i + 1; j < (int)h.array.size(); j++)
if (h.array[i] >= h.array[j] && h.array[i] != h.array[j] * 2 && i != j && h.array[i] != 0 && h.array[j] != 0) {
tmp = h;
tmp.array[i] -= tmp.array[j];
tmp.array[j] *= 2;
tmp.op.push_back(make_pair(j + 1, i + 1));
q.push(tmp);
}
else {
swap(i, j);
if (h.array[i] >= h.array[j] && h.array[i] != h.array[j] * 2 && i != j && h.array[i] != 0 && h.array[j] != 0) {
tmp = h;
tmp.array[i] -= tmp.array[j];
tmp.array[j] *= 2;
tmp.op.push_back(make_pair(j + 1, i + 1));
q.push(tmp);
}
swap(i, j);
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%d", &a[i]);
bfs();
return 0;
}
「ZHYOI-1」游戏
题目链接:「ZHYOI-1」游戏
不会。
「ZHYOI-1」公路翻新
题目链接:「ZHYOI-1」公路翻新
我只会 50 分的方法:首先树剖+线段树区间加和区间最小用来维护边权,对于停工和施工,每次停工村改变时,找到所有的停工村,做一次广搜,知道每个点最近的停工村,这样每次询问就能直接知道最近的停工村。
时间复杂度:\(\text{I don't know}\)
code
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
inline long long read() {
register long long x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
inline void write(long long x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
#define int long long
struct Edge {
int to, val;
};
int n, m;
vector<Edge> e[MAXN];
void init() {
n = read();
for (int i = 1, u, v, w; i < n; i++) {
u = read(), v = read(), w = read();
e[u].push_back((Edge){v, w});
e[v].push_back((Edge){u, w});
}
}
int p[MAXN] = {0}, d[MAXN] = {0}, val[MAXN] = {0}, sz[MAXN] = {0}, son[MAXN] = {0};
int top[MAXN] = {0}, id[MAXN] = {0}, rk[MAXN] = {0};
void dfs1(int x, int pr, int depth) {
p[x] = pr;
d[x] = depth;
sz[x] = 1;
son[x] = -1;
for (int i = 0; i < (int)e[x].size(); i++) {
int v = e[x][i].to;
if (v != pr) {
dfs1(v, x, d[x] + 1);
val[v] = e[x][i].val;
sz[x] += sz[v];
if (son[x] == -1 || sz[v] > sz[son[x]])
son[x] = v;
}
}
}
int cnt = 0;
void dfs2(int x, int t) {
top[x] = t;
id[x] = ++cnt;
rk[cnt] = x;
if (son[x] == -1)
return;
dfs2(son[x], t);
for (int i = 0; i < (int)e[x].size(); i++) {
int v = e[x][i].to;
if (v != p[x] && v != son[x])
dfs2(v, v);
}
}
struct SegTree {
int mi[MAXN * 4], tag[MAXN * 4];
#define ls (t << 1)
#define rs (t << 1 | 1)
#define mid ((l + r) >> 1)
void pushup(int t) {
mi[t] = min(mi[ls], mi[rs]);
}
void pushdown(int t) {
if (tag[t] != 0) {
mi[ls] += tag[t];
mi[rs] += tag[t];
tag[ls] += tag[t];
tag[rs] += tag[t];
tag[t] = 0;
}
}
void build(int l, int r, int t) {
if (l == r) {
mi[t] = val[rk[l]];
tag[t] = 0;
return;
}
build(l, mid, ls);
build(mid + 1, r, rs);
pushup(t);
}
void upd(int L, int R, int l, int r, int t, int x) {
if (L <= l && r <= R) {
mi[t] += x;
tag[t] += x;
return;
}
pushdown(t);
if (L <= mid)
upd(L, R, l, mid, ls, x);
if (mid < R)
upd(L, R, mid + 1, r, rs, x);
pushup(t);
}
int qry(int L, int R, int l, int r, int t) {
if (L <= l && r <= R)
return mi[t];
pushdown(t);
int ans = 2e9;
if (L <= mid)
ans = min(ans, qry(L, R, l, mid, ls));
if (mid < R)
ans = min(ans, qry(L, R, mid + 1, r, rs));
return ans;
}
} t;
void updtree(int u, int v, int x) {
while (top[u] != top[v]) {
if (d[top[u]] < d[top[v]])
swap(u, v);
t.upd(id[top[u]], id[u], 1, n, 1, x);
u = p[top[u]];
}
if (d[v] > d[u])swap(u, v);
if (u != v)
t.upd(id[v] + 1, id[u], 1, n, 1, x);
}
int st[MAXN] = {0};
bool vis[MAXN] = {false};
void bfs(int u, int v) {
queue<int> q;
while (u != v) {
st[u] = u, st[v] = v;
if (d[u] > d[v])
u = p[u];
else if (d[v] > d[u])
v = p[v];
else
u = p[u], v = p[v];
}
st[u] = u;
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n; i++)
if (st[i] == i)
q.push(i), vis[i] = true;
while (!q.empty()) {
int h = q.front();
q.pop();
for (int i = 0; i < (int)e[h].size(); i++)
if (!vis[e[h][i].to]) {
vis[e[h][i].to] = true;
st[e[h][i].to] = st[h];
q.push(e[h][i].to);
}
}
}
void chk() {
for (int i = 1; i <= n; i++)
cout << st[i] << endl;
}
void solve() {
m = read();
memset(st, -1, sizeof st);
for (int i = 1; i <= m; i++) {
int op, x, y, v;
op = read();
if (op == 1) {
x = read(), v = read();
write(st[x]), putchar('\n');
if (st[x] != -1)
updtree(x, st[x], v);
}
else if (op == 2) {
x = read(), y = read();
bfs(x, y);
}
else {
x = read();
if (son[x] == -1)
putchar('-'), putchar('1'), putchar('\n');
else
write(t.qry(id[x] + 1, id[x] + sz[x] - 1, 1, n, 1)), putchar('\n');
}
}
}
signed main() {
init();
dfs1(1, 1, 1);
dfs2(1, 1);
t.build(1, n, 1);
solve();
return 0;
}