2022赛前模测 提高组验题- 18
问题 A: 【2022NOIP联测2 10月2日】二分图排列
WA 15:为了让字典序最小,从前往后能改就改,我发现一个要向后连边的数一定不能被前面的数连过,所以它一定是前缀最大值,变相反数一定小于后面所以只需要和左侧的比较,就有几个判断,如果小于前缀Max就被连边,如果修改后小于被连边的最大值那就不修改,如果不修改依然小于下限,那就无解。
根据上面的错误结论,发现第二个数一定可以为负,但是这样就使被连边集合的mx变大了,可能导致误判为不合法。
如果排列中存在长度为3的下降序列,则图中一定存在奇环,所以修改后的排列a一定可以划分为不超过2个上升序列,即序列只能下降0次或1次。先倒序判断一下合法性,就可以在合法的基础上贪心地选了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 2; const int inf = 0x3f3f3f3f; int T, n, a[maxn], f[maxn][2]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void solve() { n = read(); for(int i=1; i<=n; i++) { a[i] = read(); f[i][0] = f[i][1] = -inf; } f[n+1][0] = f[n+1][1] = inf; a[n+1] = inf; for(int i=n; i>=1; i--) { for(int j=0; j<2; j++) { int x = j ? -a[i] : a[i]; if(x < a[i+1]) f[i][j] = max(f[i][j], f[i+1][0]); if(x < -a[i+1]) f[i][j] = max(f[i][j], f[i+1][1]); if(x < f[i+1][0]) f[i][j] = max(f[i][j], a[i+1]); if(x < f[i+1][1]) f[i][j] = max(f[i][j], -a[i+1]); } if(f[i][0] == -inf && f[i][1] == -inf) { printf("NO\n"); return; } } printf("YES\n"); int l1 = -inf, l2 = -inf; for(int i=1; i<=n; i++) { if(-a[i] > l1) { l1 = -a[i]; printf("%d ", -a[i]); } else if(-a[i] > l2 && -a[i] < f[i][1]) { l2 = -a[i]; printf("%d ", -a[i]); } else { l1 = a[i]; printf("%d ", a[i]); } if(l1 < l2) swap(l1, l2); } printf("\n"); } int main() { T = read(); while(T--) solve(); return 0; }
问题 B: 【2022NOIP联测2 10月2日】最短路问题 V3
我把我写的这个改了改格式去最短路的专题里都能A某些东西,比如:信使,对,这题的数据很水,但是我把它交到accoders上不是T了而是错了!!WA 20……这有点离谱?然后注释掉的就是这个B的错误写法:有大佬知道它为什么不对吗***
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 500; const ll inf = 1e17; int n, m, q, ff[maxn], stk[maxn], cnt, id[maxn]; ll ans, dis[maxn]; bool vis[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int next, to, w; }a[maxn<<1], e[maxn<<1]; int len, tot, head[maxn], h[maxn]; void add(int x, int y, int w) { a[++len].to = y; a[len].next = head[x]; a[len].w = w; head[x] = len; } void add_tree(int x, int y, int w) { e[++tot].to = y; e[tot].next = h[x]; e[tot].w = w; h[x] = tot; } inline void New(int x) {if(id[x]) return; stk[++cnt] = x; id[x] = cnt;} int fa[maxn], dep[maxn], siz[maxn], son[maxn], top[maxn]; void find_heavy_edge(int u, int fat, int depth) { //printf("u = %d\n", u); fa[u] = fat; dep[u] = depth; siz[u] = 1; son[u] = 0; int maxsize = 0; for(int i=h[u]; i; i=e[i].next) { int v = e[i].to; if(dep[v]) continue; dis[v] = dis[u] + e[i].w; find_heavy_edge(v, u, depth+1); siz[u] += siz[v]; if(siz[v] > maxsize) { maxsize = siz[v]; son[u] = v; } } } void connect_heavy_edge(int u, int ancestor) { top[u] = ancestor; if(son[u]) { connect_heavy_edge(son[u], ancestor); } for(int i=h[u]; i; i=e[i].next) { int v = e[i].to; if(v == son[u] || v == fa[u]) continue; connect_heavy_edge(v, v); } } int LCA(int x, int y) { while(top[x] != top[y]) { if(dep[x] < dep[y]) swap(x, y); x = fa[top[x]]; //printf("x = %d y = %d\n", x, y); } if(dep[x] > dep[y]) swap(x, y); return x; } int find(int x) { if(x == ff[x]) return x; return ff[x] = find(ff[x]); } queue<int> qu; ll d[44][maxn]; void spfa(int st) { for(int i=1; i<=n; i++) d[id[st]][i] = inf; d[id[st]][st] = 0; vis[st] = 1; qu.push(st); while(!qu.empty()) { int x = qu.front(); qu.pop(); vis[x] = 0; for(int i=head[x]; i; i=a[i].next) { int y = a[i].to; if(d[id[st]][y] > d[id[st]][x] + a[i].w) { d[id[st]][y] = d[id[st]][x] + a[i].w; if(!vis[y]) { vis[y] = 1; qu.push(y); } } } } } int main() { //freopen("1.in", "r", stdin); n = read(); m = read(); for(int i=1; i<=n; i++) ff[i] = i; for(int i=1; i<=m; i++) { int u = read(), v = read(), w = read(); add(u, v, w); add(v, u, w); int fx = find(u), fy = find(v); if(fx == fy) { New(u); New(v); continue; } ff[fx] = fy; add_tree(u, v, w); add_tree(v, u, w); } find_heavy_edge(1, 0, 1); connect_heavy_edge(1, 1); for(int i=1; i<=cnt; i++) { spfa(stk[i]); } /*q = read(); while(q--) { int u = read(), v = read(); int lca = LCA(u, v); ans = dis[u] + dis[v] - dis[lca] - dis[lca]; for(int i=1; i<=cnt; i++) { ans = min(ans, d[i][u]+d[i][v]); } printf("%lld\n", ans); }*/ ll res = 0; for(int i=2; i<=n; i++) { int lca = LCA(1, i); res = dis[i] - dis[lca] - dis[lca]; for(int j=1; j<=cnt; j++) { res = min(res, d[j][1]+d[j][i]); } //printf("res[%d] = %lld\n", i, res); ans = max(ans, res); } printf("%lld\n", ans); return 0; }
一定要建一棵最小生成树吗??
我又去鹤了一个,它A了,但我还是想知道为什么以上不对……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 50; const ll inf = 1e17; typedef pair<ll, int> paint; int n, m, q, ff[maxn], spc[maxn]; ll ans, dis[50][maxn], gap[maxn]; bool vs[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct edge { int to, w, next, op; }a[maxn<<1]; int head[maxn], len; struct node2 { int u, v, w; bool operator < (const node2 &T) const { return w < T.w; } }s[maxn]; priority_queue <paint, vector<paint>, greater<paint> > sml; void dij(int st, ll dis[]) { memset(vs, 0, sizeof(vs)); dis[st] = 0; sml.push(make_pair(dis[st], st)); while(!sml.empty()) { int u = sml.top().second; sml.pop(); if(vs[u]) continue; vs[u] = 1; for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(dis[v] > dis[u] + a[i].w) { dis[v] = dis[u] + a[i].w; sml.push(make_pair(dis[v], v)); } } } } void add(int x, int y, int w, int op) { a[++len] = edge{y, w, head[x], op}; head[x] = len; if(op) { if(!vs[x]) spc[++spc[0]] = x; if(!vs[y]) spc[++spc[0]] = y; vs[x] = vs[y] = 1; } } int find(int x) { if(x == ff[x]) return x; return ff[x] = find(ff[x]); } void un(int x, int y) { ff[find(x)] = find(y); } void Kru() { sort(s+1, s+1+m); for(int i=1; i<=n; i++) ff[i] = i; for(int i=1; i<=m; i++) { if(find(s[i].u) != find(s[i].v)) { add(s[i].u, s[i].v, s[i].w, 0); add(s[i].v, s[i].u, s[i].w, 0); un(s[i].u, s[i].v); } else add(s[i].u, s[i].v, s[i].w, 1), add(s[i].v, s[i].u, s[i].w, 1); } } int dep[maxn], dad[maxn][30]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1; dad[u][0] = fa; int t = log2(dep[u]) + 1; for(int i=1; i<=t; i++) dad[u][i] = dad[dad[u][i-1]][i-1]; for(int i=head[u]; i; i=a[i].next) { int to = a[i].to; if(to == fa || a[i].op) continue; gap[to] = gap[u] + a[i].w; dfs(to, u); } } int LCA(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i=18; i>=0; i--) { if(dep[dad[x][i]] >= dep[y]) x = dad[x][i]; } for(int i=18; i>=0; i--) { if(dad[x][i] != dad[y][i]) x = dad[x][i], y = dad[y][i]; } return x == y ? x : dad[x][0]; } int main() { n = read(); m = read(); for(int i=1; i<=m; i++) { int u = read(), v = read(), w = read(); s[i] = {u, v, w}; } Kru(); memset(dis, 0x3f, sizeof(dis)); for(int i=1; i<=spc[0]; i++) dij(spc[i], dis[i]); dfs(1, 0); q = read(); while(q--) { int u = read(), v = read(), lca = LCA(u, v); ans = gap[u] + gap[v] - 2 * gap[lca]; for(int i=1; i<=spc[0]; i++) ans = min(ans, dis[i][u]+dis[i][v]); printf("%lld\n", ans); } return 0; }
upd 10.2 17:32
并不需要建一棵最小生成树,是的就是树剖写挂了%%%TSTYFST%%%
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 500; const ll inf = 1e17; int n, m, q, ff[maxn], stk[maxn], cnt, id[maxn]; ll ans, dis[maxn]; bool vis[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int next, to, w; }a[maxn<<1], e[maxn<<1]; int len, tot, head[maxn], h[maxn]; void add(int x, int y, int w) { a[++len].to = y; a[len].next = head[x]; a[len].w = w; head[x] = len; } void add_tree(int x, int y, int w) { e[++tot].to = y; e[tot].next = h[x]; e[tot].w = w; h[x] = tot; } inline void New(int x) {if(id[x]) return; stk[++cnt] = x; id[x] = cnt;} int fa[maxn], dep[maxn], siz[maxn], son[maxn], top[maxn]; void find_heavy_edge(int u, int fat, int depth) { //printf("u = %d\n", u); fa[u] = fat; dep[u] = depth; siz[u] = 1; son[u] = 0; int maxsize = 0; for(int i=h[u]; i; i=e[i].next) { int v = e[i].to; if(dep[v]) continue; dis[v] = dis[u] + e[i].w; find_heavy_edge(v, u, depth+1); siz[u] += siz[v]; if(siz[v] > maxsize) { maxsize = siz[v]; son[u] = v; } } } void connect_heavy_edge(int u, int ancestor) { top[u] = ancestor; if(son[u]) { connect_heavy_edge(son[u], ancestor); } for(int i=h[u]; i; i=e[i].next) { int v = e[i].to; if(v == son[u] || v == fa[u]) continue; connect_heavy_edge(v, v); } } int LCA(int x, int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; //printf("x = %d y = %d\n", x, y); } if(dep[x] > dep[y]) swap(x, y); return x; } int find(int x) { if(x == ff[x]) return x; return ff[x] = find(ff[x]); } queue<int> qu; ll d[44][maxn]; void spfa(int st) { for(int i=1; i<=n; i++) d[id[st]][i] = inf; d[id[st]][st] = 0; vis[st] = 1; qu.push(st); while(!qu.empty()) { int x = qu.front(); qu.pop(); vis[x] = 0; for(int i=head[x]; i; i=a[i].next) { int y = a[i].to; if(d[id[st]][y] > d[id[st]][x] + a[i].w) { d[id[st]][y] = d[id[st]][x] + a[i].w; if(!vis[y]) { vis[y] = 1; qu.push(y); } } } } } int main() { //freopen("1.in", "r", stdin); n = read(); m = read(); for(int i=1; i<=n; i++) ff[i] = i; for(int i=1; i<=m; i++) { int u = read(), v = read(), w = read(); add(u, v, w); add(v, u, w); int fx = find(u), fy = find(v); if(fx == fy) { New(u); New(v); continue; } ff[fx] = fy; add_tree(u, v, w); add_tree(v, u, w); } find_heavy_edge(1, 0, 1); connect_heavy_edge(1, 1); for(int i=1; i<=cnt; i++) { spfa(stk[i]); } q = read(); while(q--) { int u = read(), v = read(); int lca = LCA(u, v); ans = dis[u] + dis[v] - dis[lca] - dis[lca]; for(int i=1; i<=cnt; i++) { ans = min(ans, d[i][u]+d[i][v]); } printf("%lld\n", ans); } return 0; }
但是求个最小生成树也不是不可以,Cat又把鹤的题解的版本改成了ShuLianPouFen
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 50; const ll inf = 1e17; typedef pair<ll, int> paint; int n, m, q, ff[maxn], spc[maxn]; ll ans, gap[maxn], dis[50][maxn]; bool vs[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct edge { int u, v, w; bool operator < (const edge &T) const { return w < T.w; } }s[maxn]; struct node { int next, to, w, op; }a[maxn<<1]; int head[maxn], len; void add(int x, int y, int w, int op) { //printf("op = %d\n", op); a[++len] = {head[x], y, w, op}; head[x] = len; if(op) { if(!vs[x]) spc[++spc[0]] = x; if(!vs[y]) spc[++spc[0]] = y; vs[x] = vs[y] = 1; } } int find(int x) { if(x == ff[x]) return x; return ff[x] = find(ff[x]); } void un(int x, int y) {ff[find(x)] = find(y);} void Kru() { sort(s+1, s+1+m); for(int i=1; i<=m; i++) { if(find(s[i].u) != find(s[i].v)) { add(s[i].u, s[i].v, s[i].w, 0); add(s[i].v, s[i].u, s[i].w, 0); un(s[i].u, s[i].v); } else add(s[i].u, s[i].v, s[i].w, 1), add(s[i].v, s[i].u, s[i].w, 1); } } int fa[maxn], dep[maxn], son[maxn], siz[maxn], top[maxn]; void find_heavy_edge(int u, int fat, int depth) { //printf("u = %d", u); fa[u] = fat; dep[u] = depth; son[u] = 0; siz[u] = 1; int maxsize = 0; //printf("head[%d] = %d\n", u, head[u]); for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; //printf("dep[%d] = %d\n", v, dep[v]); //printf("op = %d\n", a[i].op); if(dep[v] || a[i].op) continue; gap[v] = gap[u] + a[i].w; //printf("gap[%d] = %lld\n", v, gap[v]); find_heavy_edge(v, u, depth+1); siz[u] += siz[v]; if(siz[v] > maxsize) { maxsize = siz[v]; son[u] = v; } } } void connect_heavy_edge(int u, int ancestor) { //printf("------u = %d\n", u); top[u] = ancestor; if(son[u]) { connect_heavy_edge(son[u], ancestor); } for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; //printf("v = %d\n", v); //if(v == 3) exit(0); if(v == son[u] || v == fa[u] || a[i].op) continue; connect_heavy_edge(v, v); } } int LCA(int x, int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x, y); return x; } priority_queue<paint, vector<paint>, greater<paint> > sml; void dij(int st, ll dis[]) { memset(vs, 0, sizeof(vs)); dis[st] = 0; sml.push(make_pair(dis[st], st)); while(!sml.empty()) { int u = sml.top().second; sml.pop(); if(vs[u]) continue; vs[u] = 1; for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(dis[v] > dis[u] + a[i].w) { dis[v] = dis[u] + a[i].w; sml.push(make_pair(dis[v], v)); } } } } int main() { n = read(); m = read(); for(int i=1; i<=m; i++) { int u = read(), v = read(), w = read(); s[i] = (edge){u, v, w}; } for(int i=1; i<=n; i++) ff[i] = i; Kru(); find_heavy_edge(1, 0, 1); //printf("111\n\n\n"); connect_heavy_edge(1, 1); memset(dis, 0x3f, sizeof(dis)); for(int i=1; i<=spc[0]; i++) dij(spc[i], dis[i]); q = read(); while(q--) { int u = read(), v = read(), lca = LCA(u, v); ans = gap[u] + gap[v] - 2 * gap[lca]; //printf("ans = %lld\n", ans); for(int i=1; i<=spc[0]; i++) ans = min(ans, dis[i][u]+dis[i][v]); printf("%lld\n", ans); } return 0; }
问题 C: 【2022NOIP联测2 10月2日】捡石子游戏
官方题解不错我要了:
不能用权值最小的节点为根求深度然后判奇偶性,不一定所有的点都能到达点权最小的那个,但是所有的点都有一个边界,还是对每个点dfs吧。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3003; const int inf = 0x3f3f3f3f; int n, c[maxn]; bool f; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int next, to; }a[maxn<<1]; int head[maxn], len; void add(int x, int y) { a[++len].to = y; a[len].next = head[x]; head[x] = len; } int dfs(int u, int fa) { for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(v != fa && c[u] > c[v] && !dfs(v, u)) return 1; } return 0; } int main() { n = read(); for(int i=1; i<=n; i++) c[i] = read(); for(int i=1; i<n; i++) { int u = read(), v = read(); add(u, v); add(v, u); } for(int i=1; i<=n; i++) { if(dfs(i, 0)) { printf("%d ", i); f = 1; } } if(!f) printf("-1"); return 0; }
问题 D: 【2022NOIP联测2 10月2日】凹函数
咕了……
时光花火,水月星辰