国庆做题记录(含有一些trick)

news/2025/10/8 22:18:37/文章来源:https://www.cnblogs.com/Tiger-Rory/p/19123768

这篇文章信息量偏大,请谨慎阅读,注意高效利用右边的目录。

1.1 二分

关联博文:Atserkcn-0/1分数规划

P1404 平均数

既然要让子串平均数最大,那就二分平均数,判断能否达到即可。复杂度 \(O(n\log V)\)

关联题目:[2025国庆集训Day2C] course

点击查看代码
signed main(){ read(n), read(m); for(register int i = 1; i <= n; i++) read(a[i]), a[i] *= 10000, Max = max(Max, a[i]); int l = 0, r = Max; while(l <= r) {int mid = (l + r) >> 1; bool flag = 0; int minn = 0; for(register int i = 1; i <= n; i++) {s[i] = s[i - 1] + (a[i] - mid); if(i >= m) {minn = min(minn, s[i - m]); if(s[i] > minn) {flag = 1; break; }} } if(flag) l = mid + 1; else r = mid - 1; }fwr(l / 10);return 0;
}

P4047 [JSOI2010] 部落划分

要求距离最远的部落距离最小,依然二分答案。但是判定时需要贪心地选择最近的两个部落合并,需要用到并查集维护集合。时间复杂度 \(O(n^2\log V\times \alpha(n))\)

点击查看代码
int find(register int x) {return fa[x] == x ? x : fa[x] = find(fa[x]); 
}
double mx, my; 
inline bool chk(double mid) {for(register int i = 1; i <= n; i++) fa[i] = i; int cnt = 0; for(register int i = 1; i <= n; i++) for(register int j = 1; j <= n; j++) {if((x[j] - x[i]) * (x[j] - x[i]) + (y[j] - y[i]) * (y[j] - y[i]) <= mid) {fa[find(i)] = find(j); }} for(register int i = 1; i <= n; i++) if(find(i) == i) cnt++; return cnt >= k; 
}
int main(){read(n); read(k); for(register int i = 1; i <= n; i++) {read(x[i]), read(y[i]);mx = max(1.0 * x[i], mx), my = max(1.0 * y[i], my);  } double l = 0, r = mx * mx + my * my, mid; while(r - l > 1e-4) {mid = (l + r) / 2; if(chk(mid)) l = mid; else r = mid; } printf("%.2lf\n", sqrt(l)); return 0;
}

P6004 Wormhole Sort S

奶牛为什么要钻虫洞?

要求最大化被奶牛用来排序的虫洞宽度的最小值,还是二分答案。

考虑二分最小虫洞宽度。先对每个虫洞的宽度排序,然后判定的时候把满足 \(w\ge mid\) 的虫洞两端点用并查集合并到一起,最后看每个 \(p_i\)\(i\) 是否在同一集合内就行了。时间复杂度 \(O(n\log n + n\log V)\)

点击查看代码
struct Edge {int u, v, w; 
} a[N]; 
int n, m, p[N], fa[N], cw[N], tot, ans;  
int find(register int x) {return fa[x] == x ? x : fa[x] = find(fa[x]); 
}
inline bool cmp(const Edge &x, const Edge &y) {return x.w > y.w; 
}
inline bool chk(register int x) {for(register int i = 1; i <= n; i++) fa[i] = i; for(register int i = 1; i <= m; i++) { if(a[i].w < x) break; register int f1 = find(a[i].u), f2 = find(a[i].v);  fa[f1] = f2; } for(register int i = 1; i <= tot; i++) {if(find(p[cw[i]]) != find(cw[i])) return false; } return true; 
}
int main(){read(n); read(m); for(register int i = 1; i <= n; i++) {read(p[i]); if(p[i] != i) cw[++tot] = i; }    if(!tot) return fwr(-1), 0; for(register int i = 1; i <= m; i++) read(a[i].u), read(a[i].v), read(a[i].w); sort(a + 1, a + m + 1, cmp);  int l = a[m].w, r = a[1].w, mid; while(l <= r) {mid = (l + r) >> 1; if(chk(mid)) l = mid + 1, ans = mid; else r = mid - 1; } fwr(ans);  return 0;
}

P4064 [JXOI2017] 加法

可以二分题目要求的 \(\min\{a_i\}\),但是判定很麻烦。

我们贪心地想,从左往右扫一遍,遇到小于 \(mid\)\(a_i\) 就直接用包含它的 \(l,r\) 执行操作直到它足够大,但是这个操作对区间内其他元素也有影响,要用树状数组维护。

但是区间的使用是有限制的,考虑取用区间时按照右端点排序,这样可以贡献到更多后面未知元素。同时要弹出右端点在 \(i\) 之前的区间,用优先队列可以实现这一整个过程。

参考的题解说预先要按照左端点排序,但是事实上与优先队列采用一致的排序方式也不影响。

const int N = 2e5 + 5; 
const long long INF = 1e18; 
int T, n, m, k, a;
long long A[N], c[N]; 
struct Segs {int l, r; bool operator < (const Segs &rhs) const { return r < rhs.r; }
} seg[N]; 
inline int lbt(register int x) { return x & -x; }
inline void upd(register int x, register int d) { while(x <= n) c[x] += d, x += lbt(x); return; }
inline int qry(register int x) { int res = 0; while(x) res += c[x], x -= lbt(x); return res; } 
inline bool cmp(const Segs &x, const Segs & y) {if(x.l == y.l) return x.r > y.r; return x.l < y.l;              
} 
priority_queue<Segs> q; 
inline void init() {while(!q.empty()) q.pop(); memset(c, 0, sizeof(c)); return; 
} 
inline bool chk(int x) { init(); int rec = 1, cnt = 0; for(int i = 1; i <= n; i++) upd(i, A[i] - A[i - 1]);  for(int i = 1; i <= n; i++) { while(rec <= m && seg[rec].l <= i) {q.push(seg[rec]);rec++;  }while(qry(i) < x && !q.empty()) { Segs t; do {t = q.top(); q.pop(); } while(t.r < i && !q.empty());  cnt++; if(cnt > k || t.r < i) return false; upd(t.l, a); upd(t.r + 1, -a);  } if(qry(i) < x) return false;  } return true; 
}
void Main() {read(n); read(m); read(k); read(a);  long long l = INF, r = 0, mid, ans = 0; for(register int i = 1; i <= n; i++) {read(A[i]); l = min(l, A[i]); r = max(r, A[i]); } for(register int i = 1; i <= m; i++) {read(seg[i].l); read(seg[i].r);  }sort(seg + 1, seg + m + 1, cmp); r += k * a; while(l <= r) {mid = (l + r) >> 1; if(chk(mid)) l = mid + 1, ans = mid; else r = mid - 1; } fwr(ans); return putchar('\n'), void(); 
}signed main(){read(T); while(T--) Main(); return 0;
}

CF1731D Valiant's New Map

本题有个技巧是二分判定时预先把矩阵变成 01 矩阵,再做二维前缀和找和为 \(0\) 的正方形就行了。

P2824 [HEOI2016/TJOI2016] 排序

放我做题计划里多久了?忘了

一眼线段树。但是这题实际上是离线的,线段树主要起到辅助二分判定的作用。

正常排序是 \(O(n\log n)\) 的,显然太慢。本题需要一个更快捷的排序,那就是 01 排序。

01 排序只需要记一下 \(1\) 的个数,然后区间统一修改就行了。应用到本题,即二分答案 \(mid\),然后大于等于 \(mid\) 的全标记成 \(1\),否则标记成 \(0\),如果判定后 \(mid\)\(1\) 左端点后移,否则右端点前移。线段树上查询和上传修改操作全部都是 \(O(\log n)\) 的,判定复杂度就是 \(O(n\log n)\),总复杂度 \(O(n\log^2 n)\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5; 
int n, m, q; 
int a[N], op[N], L[N], R[N]; 
struct SGT {int l, r, val, lzy; 
} tr[N << 2]; 
void pushup(int rt) {tr[rt].val = tr[(rt << 1)].val + tr[(rt << 1 | 1)].val; return; 
}
void rebuild(int l, int r, int rt, int mid) {tr[rt].l = l, tr[rt].r = r, tr[rt].lzy = 0; if(l == r) {if(a[l] >= mid) tr[rt].val = 1; else tr[rt].val = 0; return; } int md = (l + r) >> 1; rebuild(l, md, (rt << 1), mid); rebuild(md + 1, r, (rt << 1 | 1), mid); pushup(rt); return; 
}
void pushdown(int rt) {if(tr[rt].lzy) {tr[rt << 1].lzy = tr[rt << 1 | 1].lzy = tr[rt].lzy; int mid = (tr[rt].l + tr[rt].r) >> 1; if(tr[rt].lzy == 1) tr[(rt << 1)].val = mid - tr[rt].l + 1, tr[(rt << 1 | 1)].val = tr[rt].r - mid; else tr[rt << 1].val = tr[rt << 1 | 1].val = 0;  tr[rt].lzy = 0; } return; 
} 
int qry(int l, int r, int rt, int ql, int qr) {if(ql <= l && r <= qr) return tr[rt].val; if(ql > r || qr < l) return 0; pushdown(rt); int mid = (l + r) >> 1; return qry(l, mid, rt << 1, ql, qr) + qry(mid + 1, r, rt << 1 | 1, ql, qr); 
}
int check(int l, int r, int rt, int p) {if(l == p && r == p) return tr[rt].val; pushdown(rt); int mid = (l + r) >> 1; if(p <= mid) return check(l, mid, (rt << 1), p); else return check(mid + 1, r, (rt << 1 | 1), p); 
}
void upd(int l, int r, int rt, int ql, int qr, int v) {if(ql <= l && qr >= r) {tr[rt].val = v * (r - l + 1); tr[rt].lzy = v ? 1 : -1; return; } if(ql > r || qr < l) return; pushdown(rt); int mid = (l + r) >> 1; upd(l, mid, (rt << 1), ql, qr, v); upd(mid + 1, r, rt << 1 | 1, ql, qr, v); pushup(rt); 
}
bool chk(int mid) {rebuild(1, n, 1, mid); for(int i = 1; i <= m; i++) {int cnt1 = qry(1, n, 1, L[i], R[i]); if(op[i] == 0) {upd(1, n, 1, R[i] - cnt1 + 1, R[i], 1); upd(1, n, 1, L[i], R[i] - cnt1, 0); } else {upd(1, n, 1, L[i], L[i] + cnt1 - 1, 1); upd(1, n, 1, L[i] + cnt1, R[i], 0);   }} return check(1, n, 1, q); 
}
int main(){cin >> n >> m; for(int i = 1; i <= n; i++) {cin >> a[i]; } for(int i = 1; i <= m; i++) {cin >> op[i] >> L[i] >> R[i]; } cin >> q; int l = 1, r = n, mid, ans; while(l <= r) {mid = (l + r) >> 1; if(chk(mid)) l = mid + 1, ans = mid; else r = mid - 1; }cout << ans; return 0;
}

ABC136E Max GCD

本文可以在题解区找到。

多好的一道思维题!

蒟蒻觉得大佬们双指针贪心部分讲得有些简略,故写一篇题解来具体说说自己的想法。

首先,我们要发现一个重要的性质:记最终的答案为 \(ans\),那么 \(ans\) 一定整除 \(\sum_{i=1}^{n} A_i\)。因为无论怎么操作序列的和都不变,且最后必须保证 \(ans\) 是所有 \(A_i\) 的公约数。

那么,我们记 \(sum=\sum_{i=1}^{n} A_i\),则 \(ans\) 一定是 \(sum\) 的因子。那就需要枚举 \(sum\) 的因子,合法的最大因子就是 \(ans\)

接下来就是判断是否合法。当考察因子 \(x\) 时,考虑记录每个 \(B_i=A_i \bmod x\),并将它们从小到大排序,接着进行双指针扫描,贪心地计算所需操作次数 \(cnt\),若 \(cnt\le k\) 则合法。记左指针为 \(l\),右指针为 \(r\),具体贪心实现如下:

  • \(B_l+B_r=x\),那么操作 \(B_l\)\(B_l,B_r\) 就可以都变成 \(0\)\(cnt\) 加上 \(B_l\),两个指针都向中间靠 \(1\) 个坐标。

  • \(B_l+B_r<x\),那么钦定操作 \(B_l\) 次使得 \(B_l\) 变成 \(0\),则 \(B_r\) 变成 \(B_r+B_l\)\(cnt\) 加上 \(B_l\),左指针向中间靠 \(1\) 个坐标。

  • \(B_l+B_r>x\),那么钦定操作 \(x-B_r\) 次使得 \(B_r\) 变成 \(x\),相当于变成 \(0\),则 \(B_l\) 变成 \(B_l-x+B_r\)\(cnt\) 加上 \(x-B_r\),右指针向中间靠 \(1\) 个坐标。

如果你对后两个操作有疑问,如“为什么要这样钦定”,请代入前提条件“已经将 \(B_i\) 从小到大排序”。

那么本题就完成了,时间复杂度是 \(O(n\log n\sqrt {sum})\)。但实际上肯定要比这个快,因为 \(O(n\log n)\) 是检查因数时排序的复杂度。

提交记录。

1.2 贪心

P8898 Feeding the Cows B

注意到有的地方如果种了草,那么它所能影响的范围内均不需要种草。那就考虑在从左往右扫的时候,如果 \(i\) 没被覆盖,就不断从 \(i+k\) 往前看能不能种,如果能种就直接跳出。

时间复杂度大概 \(O(n\log n)\)

P3545 [POI 2012] HUR-Warehouse Store

经典的贪心+堆维护。

最优肯定是全部都满足,但是大概率不可能。考虑能满足就满足,遇到不能满足的就把前面满足的人里买的最多的那个人踢出去(如果踢掉他就能满足当前的人),这样就能保证答案最大化。

用大根堆维护即可,复杂度 \(O(n\log n)\)

struct node {int id, mon; bool operator < (const node &rhs) const {return mon < rhs.mon; }   
};
priority_queue<node> q; 
signed main() {rd(n); for(int i = 1; i <= n; i++) {rd(a[i]); }for(int i = 1; i <= n; i++) {rd(b[i]); } for(int i = 1; i <= n; i++) {sum += a[i]; if(sum < b[i]) {if(!q.empty() && q.top().mon > b[i]) {vis[q.top().id] = 0; sum += q.top().mon; q.pop(); --ans;} }if(sum >= b[i]) {sum -= b[i]; q.push((node){i, b[i]}); vis[i] = 1; ++ans; }} fp(ans); hh(); for(int i = 1; i <= n; i++, kg()) {if(vis[i]) fp(i); } return 0;
}

P4053 [JSOI2007] 建筑抢修

贪心+堆模型。

限制时间短的建筑肯定更要紧,所以先按照它升序排序。

接下来就是自然的贪心。如果有建筑需要报废,那必然选择报废维修时间最长那个来争取维修更多建筑。

struct Build {int t1, t2; 
} a[N];      
priority_queue<pii>q; 
bool cmp(Build x, Build y) {return x.t2 < y.t2; 
} 
signed main() {rd(n); for(int i = 1; i <= n; i++) {rd(a[i].t1); rd(a[i].t2); }sort(a + 1, a + n + 1, cmp); for(int i = 1; i <= n; i++) {sum += a[i].t1; q.push({a[i].t1, i}); if(sum <= a[i].t2) ans++; else sum -= q.top().first, q.pop(); } fp(ans); return 0;
}

1.3 搜索 & 模拟

P12684 叉叉学习魔法

考虑直接 bfs,容易想到记录当前位置、最小步数 \(t1\) 和最少魔法使用次数 \(t2\),用堆维护可以做到 \(O(nm\log (nm))\)。但是这样会超时倒闭,所以考虑用 01bfs,将 \(t1+1\) 的新状态加到队尾,\(t2+1\) 的新状态加到队头,这样相当于线性维护了之前的堆,可以把 \(\log\) 去掉做到 \(O(nm)\)。当然,在此之前 \(t1,t2\) 没改的状态要从队头取出,否则会破坏单调性。

#include <iostream>
#include <deque> 
#include <vector>
using namespace std;
const int N = 5005; 
int n, m, x1, y1, x2, y2; 
char a[N][N];  
bool vis[N][N];  
struct node {int x, y, t1, t2; bool operator < (const node &rhs) const {if(t1 != rhs.t1) return t1 > rhs.t1; return t2 > rhs.t2; }
}; 
deque<node> q; 
vector<node> v1, v2; 
const int dx1[] = {-1, 1, 0, 0}, dy1[] = {0, 0, -1, 1}; 
const int dx2[] = {-1, -1, 1, 1}, dy2[] = {-1, 1, -1, 1}; 
void _01bfs() {q.push_front((node){x1, y1, 0, 0}); while(!q.empty()) {node u = q.front(); while(!q.empty() && u.t1 == q.front().t1 && u.t2 == q.front().t2) {u = q.front(); q.pop_front(); if(u.x == x2 && u.y == y2) {printf("%d %d", u.t1, u.t2); return; } if(vis[u.x][u.y]) continue; vis[u.x][u.y] = 1; for(int i = 0; i < 4; i++) {int nx = u.x + dx1[i], ny = u.y + dy1[i]; if(!nx || !ny || nx == n + 1 || ny == m + 1 || a[nx][ny] == '#') continue; v1.push_back({nx, ny, u.t1 + 1, u.t2}); }for(int i = 0; i < 4; i++) {int nx = u.x + dx2[i], ny = u.y + dy2[i]; if(!nx || !ny || nx == n + 1 || ny == m + 1 || a[nx][ny] == '#') continue; v2.push_back({nx, ny, u.t1, u.t2 + 1}); }}for(auto v : v2) q.push_front(v); for(auto v : v1) q.push_back(v); v1.clear(), v2.clear(); }printf("-1 -1"); return; 
}
int main() {scanf("%d %d", &n, &m); for(int i = 1; i <= n; i++) {scanf("%s", a[i] + 1); for(int j = 1; j <= m; j++) { if(a[i][j] == 'X') x1 = i, y1 = j; else if(a[i][j] == 'W') x2 = i, y2 = j;  }} _01bfs();  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/932001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】如何移动材料/文件夹

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【PhysUnits】15.9 引入P1后的右移运算(shr.rs) - 详解

【PhysUnits】15.9 引入P1后的右移运算(shr.rs) - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

[论文阅读]PPT: Backdoor Attacks on Pre-trained Models via Poisoned Prompt Tuning - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

10. 模型与视图

一、模型与视图模型/视图架构包含三部分:模型(Model)是应用对象,用来表示数据;视图(View)是模型的用户界面,用来显示数据;委托(Delegate,也被称为 代理)可以定制数据的渲染和编辑方式。通过数据和界面进行…

网站域名备案信息查询wordpress无法查看站点

为啥我会使用pgbackrest进行备份&#xff1f;因为postgresql没有自带的差异备份工具。。。而我们在生产环境上&#xff0c;一般都需要用到差异备份或者增量备份。我们的备份策略基本是&#xff0c;1天1次完整备份&#xff0c;1个小时1次差异备份。如果只需要完整备份&#xff0…

[KaibaMath]1004 关于f(x,y) = [x]+[y] - [x+y]的平移稳定性

[KaibaMath]1004 关于f(x,y) = [x]+[y] - [x+y]的平移稳定性令f(x,y) = [x]+[y] - [x+y], g(x, y) = {x} + {y} - {x+y},则f(x, y) + g(x, y)= 0。 注意f(x, y)和g(x, y)均具有平移稳定性。 例如:f(x+M, y+N) = f(x,…

Mac OS 问题与技巧

docker Desktop中登录ubuntu后出现向上方向键不识别的问题:# 从 sh 切换到 bash /bin/bash通过方向键找到上一个命令: root@a8cf29654a52:/opt/csm# pwd /opt/csm root@a8cf29654a52:/opt/csm# pwd /opt/csm root@a8…

数据分析对网站建设的重要性福田营销型网站建站推广外包

文章目录 前言ts和js的区别&#xff1f;什么是Typescript的方法重载&#xff1f;Typescript中never 和 void 的区别&#xff1f;typescript 中的 is 关键字有什么用&#xff1f;TypeScript支持的访问修饰符有哪些&#xff1f;如何定义一个数组&#xff0c;它的元素可能是字符串…

黑龙江省建设教育网站查询小企业网站建设计划书

目录 1、什么是缓存 2、为什么使用Redis作为MySQL的缓存 3、缓存的更新策略 3.1、策略一&#xff1a;定期生成 3.2、策略二&#xff1a;实时生成 内存淘汰策略【面试重点】 4、缓存预热(Cache preheating)【面试重点】 5、缓存穿透(Cache penetration)【面试重点】 6、…

《算法设计与分析》第一章学习记录

一、互联网大公司的编码规范 核心目标是协同、质量、效率与安全。 1.命名规范 变量、函数、类名必须能清晰地表达其意图,避免使用 a, b, c, tmp 等无意义名称。严格遵守 camelCase、PascalCase、snake_case 等约定,并…

mcp_server

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" https://github.com/runekaagaard/mcp-alchemy"imes": { "command": "uvx", &qu…

香山红叶建设有限公司网站虚拟主机安装wordpress

一、代理模式 代理模式定义&#xff1a;为其他对象提供一种代理以控制对这个对象的访问。 上面类图中有一个订单接口类(OrderService)、一个订单实现类(OrderServiceImpl)&#xff0c;订单模块的业务相对复杂和重要&#xff0c;如果这时候要在方法执行前后加上日志&#xff0c…

2025.10 国庆集训模拟赛总结

把门视为点,找环,答案就是环的长度先预处理前缀和 然后预处理f[i]表示满足j<i且aj==ai的最大的j。 答案就变成了:第一问用树套树类结构维护 第二问直接二分第一问就行,因为第一问我们在先做了。 树套树太难写,…

详细介绍:https和http有什么区别-http各个版本有什么区别

详细介绍:https和http有什么区别-http各个版本有什么区别pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consola…

CF2150F Cycle Closing

感觉上判是否能一次完成是困难的。设两次的路径长度分别为 \(a, b\),考虑一些特殊情况。 题目一定有解,考虑取出一棵生成树。可以发现,第二次操作时的边数实际上很多,感觉上对于 \(b\) 不能限制得太小。考虑 \(a\)…

Easysearch 字段隐身之谜:source_reuse 与 ignore_above 的陷阱解析

背景问题 前阵子,社区有小伙伴在使用 Easysearch 的数据压缩功能时发现,在开启 source_reuse 和 ZSTD 后,一个字段的内容看不到了。 索引的设置如下: {......"settings": {"index": {"co…

QOJ856 Cactus 广义串并联图

题意 给定一棵仙人掌, 你需要用 \(k\) 种颜色给每个结点染色, 且保证有边相连的结点的颜色不相同, 求染色的方案数对 \(10^9+7\) 取模的结果。仙人掌定义为一张特殊的无向图, 其中每条边至多在一个简单环上。 题解 因为…

CF2152 订题

context A 除了最小的数字每种数字都会占用一次,去重后直接输出 \(2n-1\) 即可。 B 太神秘了,先咕咕咕。 C 发现如果一个区间内存在至少一个长度 \(\ge 2\) 的同色连续段,那么这个连续段可以通过删除两个同色之间的…

TortoiseSVN账号切换 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

房产中介 网站开发天津招投标天津建设工程信息网

电脑 远程桌面连接你的凭据不工作解决方法 方法/步骤 第一步我们首先需要知道远程桌面连接你的凭据不工作原因是&#xff0c;远程的电脑拒绝了访问&#xff0c;需要设置在远程的电脑上设置安全选项&#xff0c;按winR键&#xff0c;打开运行&#xff0c;输入“gpedit.msc”&a…