tech pack 1.
收录技巧题
1. CF1973E - Cat, Fox and Swaps
tag:构造、贪心;link。
可以发现有一个通过元素
,需求是覆盖区间 。
而可以通过交换
枚举区间长度,对于长度
但是还需两个特判:
- 不存在
,输出 即可。 - 对于所有
有 为一个定值 ,这样区间 也是合法的。注意到 ,所以未统计的区间有且仅有一个,加上即可。
点击查看代码
//CF1973E #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int T, n, p[N]; int main(){ scanf("%d", &T); while(T--){ scanf("%d", &n); bool flg = 1; int le = n + 1, ri = 0; for(int i = 1; i <= n; ++ i){ scanf("%d", &p[i]); if(p[i] != i){ flg = 0; le = min(le, i); ri = max(ri, i); } } if(flg){ printf("%lld\n", n * 1ll * (n + n + 1)); } else { long long ans = 0; int val = p[le] + le; for(int i = le; i <= ri; ++ i){ if(p[i] != i && val != p[i] + i){ flg = 1; } } if(!flg){ ++ ans; } swap(le, ri); ri += n; for(int i = 2; i <= n + n; ++ i){ ans += ri - le + 1; le = max(1, le - 1); ri = min(ri, n + n - i); } printf("%lld\n", ans); } } return 0; }
2. CF1973D - Cat, Fox and Double Maximum
tag:复杂度分析;link。
首先有两个方向:
又有
点击查看代码
//CF1973D #include <bits/stdc++.h> using namespace std; int T, n, k, mx; int ask(int l, int x){ cout << "? " << l << ' ' << x << endl; int p; cin >> p; return p; } bool chk(int x){ int tp = 1, cnt = 0; while(tp <= n){ tp = ask(tp, x * mx) + 1; ++ cnt; if(cnt > k){ return 0; } } return cnt == k && tp == n + 1; } int main(){ scanf("%d", &T); while(T--){ scanf("%d%d", &n, &k); for(int i = n; i >= 1; -- i){ if(ask(1, i*n) == n){ mx = i; break; } } bool flg = 0; for(int i = n / k; i >= 1; -- i){ if(chk(i)){ flg = 1; cout << "! " << i * mx << endl; break; } } if(!flg){ cout << "! -1" << endl; } int p; scanf("%d", &p); } return 0; }
3. Toyota2023SpringF - Git Gud
tag:exchange argument;link。
考虑计算每一条边的贡献。一条边在一次合并中有贡献,当且仅当这次合并两个点一端在这条边的子树中。所以计算出每个点的
用
发现一定存在一种最优解,使得每次合并后,被合并的点构成一个连通块。因为:
- 若这次合并是最后一次,显然正确;
- 否则若一次合并中合并了两个
的连通块,则一定有一个连通块还有至少 条边未合并(意味着 ),则将这个连通块先与另一连通块相邻的那个点合并,再合并另一个连通块肯定不劣。
那么就相当于:
- 枚举一个根
; - 找到一个
,满足对于树上 有 ; - 用
更新答案。
使用 exchange argument 套路,每次维护平均值最小的连通块,接在它父亲连通块的后面。
最后记得答案加上
点击查看代码
//pjudge21808 #include <bits/stdc++.h> using namespace std; const int N = 2010; int n, deg[N], rs = -1e9; vector<int> g[N]; int fa[N]; void dfs(int x, int fat){ fa[x] = fat; for(int i : g[x]){ if(i != fat){ dfs(i, x); } } } struct ufs{ int fa[N]; void init(){ for(int i = 1; i <= n; ++ i){ fa[i] = i; } } int gf(int x){ return fa[x] == x ? x : fa[x] = gf(fa[x]); } void mg(int x, int y){ fa[gf(x)] = gf(y); } } t; struct node{ int id, sum, siz; bool operator < (const node &b) const { return sum * b.siz < siz * b.sum; } }; int sum[N], ans[N], siz[N]; int calc(int rt){ dfs(rt, 0); priority_queue<node> q; for(int i = 1; i <= n; ++ i){ q.push({ i, deg[i], 1 }); sum[i] = deg[i]; ans[i] = 0; siz[i] = 1; } t.init(); while(!q.empty()){ node x = q.top(); q.pop(); if(x.id == rt || t.gf(x.id) != x.id){ continue; } int y = t.gf(fa[x.id]); ans[y] += sum[y] * siz[x.id] + ans[x.id]; sum[y] += sum[x.id]; siz[y] += siz[x.id]; q.push({ y, sum[y], siz[y] }); t.mg(x.id, y); } return ans[rt] + 3 * (n - 1); } int main(){ scanf("%d", &n); for(int i = 1; i < n; ++ i){ int u, v; scanf("%d%d", &u, &v); ++ u; ++ v; g[u].push_back(v); g[v].push_back(u); } for(int i = 1; i <= n; ++ i){ deg[i] = g[i].size() - 2; } for(int i = 1; i <= n; ++ i){ rs = max(rs, calc(i)); } printf("%d\n", rs); return 0; }
4. CCO2021 - Travelling Merchant
https://www.luogu.com.cn/problem/P7831
考虑如何求出所有
按
若一个点的所有出边都被删除,那么它的答案就确定了。枚举以它作为
点击查看代码
#include <bits/stdc++.h> using namespace std; const int N = 4e5 + 10; int n, m, ind[N], vis[N]; typedef long long ll; ll ans[N]; struct edge{ int a, b, r, p, id; } g[N]; vector<int> fr[N]; bool cmp(edge x, edge y){ return x.r > y.r; } int hd[N], top; struct Edge{ int eg, r, p, nx, id; } e[N]; int main(){ scanf("%d%d", &n, &m); int mx = 0; for(int i = 1; i <= m; ++ i){ int a, b, r, p; scanf("%d%d%d%d", &a, &b, &r, &p); g[i] = {a, b, r, p, i}; mx = max(mx, r); e[++top] = {a, r, p, hd[b], i}; hd[b] = top; ++ ind[a]; } sort(g + 1, g + m + 1, cmp); memset(ans, 0x3f, sizeof(ans)); queue<int> q; for(int i = 1; i <= n; ++ i){ if(!ind[i]){ q.push(i); } } for(int i = 1; i <= m; ++ i){ while(!q.empty()){ int x = q.front(); q.pop(); for(int i = hd[x]; i; i = e[i].nx){ if(vis[e[i].id]){ continue; } int y = e[i].eg; vis[e[i].id] = 1; if(ans[x] <= mx){ ans[y] = min(ans[y], max(ans[x] - e[i].p, (ll)e[i].r)); } -- ind[y]; if(!ind[y]){ q.push(y); } } } int a = g[i].a, b = g[i].b, r = g[i].r, p = g[i].p; if(!vis[g[i].id]){ vis[g[i].id] = 1; ans[a] = min(ans[a], (ll)r); -- ind[a]; if(!ind[a]){ q.push(a); } } } for(int i = 1; i <= n; ++ i){ if(ans[i] > mx){ ans[i] = -1; } printf("%lld ", ans[i]); } return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步