妙妙 trick 题
所有链接基本都是 luogu 链接。
大部分题是一个题单里的,小部分题可能是新知比较有意义的题目。
大多是 CF 的,不是 CF 的基本都是新知,也写进来。
2025/1/20
CF1292B(*1700)
评分个人感觉有点低了,毕竟有点偏思维。
注意到
题目给定了起点
CF1396B(*1800)
看上去是博弈,实际上确实是博弈,因为一个人可以选择一堆拿一个并且锁掉这一堆,所以发现如果最开始有一堆的数量大于其余所有堆的总数,那么先手必胜,策略是先手一直锁定这一堆。
如果没有的话,二者一定会选择当前最大的一堆并锁住,这样到最后一定会拿完所有的石头,所以直接判奇偶即可。
2025/1/21
P4008(Splay 新知)
平衡树求第
点击查看
int get_kth(int v) {
int x = rt;
while(x) {
int sum = siz(ls(x)) + 1;
if(v == sum) return x;
if(v < sum) x = ls(x);
else v -= sum, x = rs(x);
}
}
2025/1/22
CF1748E(*2300)(笛卡尔树新知)
栈顶为树根,一般会定义
然后因为笛卡尔树有堆的性质所以一段区间最小值
点击查看
void dfs(int u) {
rep(i, 1, k) dp[u][i] = 1;
if(ch[u][0]) dfs(ch[u][0]);
if(ch[u][1]) dfs(ch[u][1]);
if(ch[u][0]) rep(i, 1, k) dp[u][i] = dp[u][i] * dp[ch[u][0]][i - 1] % mod;
if(ch[u][1]) rep(i, 1, k) dp[u][i] = dp[u][i] * dp[ch[u][1]][i] % mod;
rep(i, 2, k) dp[u][i] = (dp[u][i] + dp[u][i - 1]) % mod;
}
CF2048F(*2500)(笛卡尔树新知)
跟
如上道题目所述一样,套路地定义
ABC341F
这个 blog 标题可以删掉 CF 二字了。
傻逼 trick 题,首先知道对于一条边
考虑怎么算传递集合
点击查看
rep(i, 1, n) {
memset(f, 0, sizeof f);
u = id[i];
for(auto v : e[u]) {
if(w[v] < w[u]) {
pre(j, w[u] - 1, w[v]) f[j] = max(f[j], f[j - w[v]] + g[v]);
}
}
rep(j, 0, N - 5) g[u] = max(g[u], f[j] + 1);
}
2025/1/24
P3043
有一个长度为
TQ 翻译:给每条边找一个配对的点,要求边
🐕⑩ 人类智慧题,考虑三种情况:
先挖掘性质:一个环的贡献为
- 环:是棵基环树,先选环,每个点可以选左边或者选右边,其余点方案唯一,总贡献为
。 - 树:会多出一个点不会被选择,当然是随便选一个点,其余点方案唯一,贡献为
。 - 边数大于点数的连通块:一定有点会被同时选择,不合题意,答案为
。
根据乘法原理即可,答案为
ABC348G
这个 trick 做过的,但是考场上因为好同学 Xdik 加上对整场题目的判断有严重错误在处于摆烂状态没认真想。
题目是求每个
两者都有
然后一起求的话可以分治优化一下,时间复杂度是两只
点击查看
int upd(int id, int l, int r, int x) {
int p = ++tot; t[p] = t[id];
++v(p), s(p) += b[x];
if(l == r) return p;
int mid = l + r >> 1;
if(x <= mid) ls(p) = upd(ls(id), l, mid, x);
else rs(p) = upd(rs(id), mid + 1, r, x);
return p;
}
int ask(int p, int l, int r, int k) {
if(l == r) return k * b[l];
int mid = l + r >> 1;
if(v(rs(p)) >= k) return ask(rs(p), mid + 1, r, k);
else return s(rs(p)) + ask(ls(p), l, mid, k - v(rs(p)));
}
int w(int k, int x) {
return ask(rt[x], 1, V, k) - a[x].fi;
}
CF1495E(*3200)
先咕。
2025/1/25
因为🐕 guomao 回归了然后没时间做了咕咕咕。
2025/2/4
因为放假回家过年了今天才回归。
CF827F(*3200)
拆点,我的题解。
Para 上课的时候一个很纽币的题感觉自己听懂了就写了其实也很好写。
CF888G(*2300)
暴力时空都是
放下代码:
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
#define int long long
using namespace std;
const int N = 2e5 + 5;
int n, a[N];
namespace Trie {
int rt, tot, ch[2][N << 5], l[N << 5], r[N << 5];
void ins(int& p, int x, int d) {
if (!p) p = ++tot;
if (!l[p]) l[p] = x;
r[p] = x;
if (d >= 0) ins(ch[a[x] >> d & 1][p], x, d - 1);
}
int get(int p, int x, int d) {
return (d < 0 ? 0 : ch[x >> d & 1][p] ? get(ch[x >> d & 1][p], x, d - 1) : get(ch[!(x >> d & 1)][p], x, d - 1) + (1 << d));
}
int dfs(int p, int d) {
if (!p || d < 0) return 0;
int ret = 1e18;
if (ch[0][p] && ch[1][p]) rep(i, l[ch[0][p]], r[ch[0][p]]) ret = min (ret, get(ch[1][p], a[i], d - 1) + (1 << d));
return dfs(ch[0][p], d - 1) + dfs(ch[1][p], d - 1) + ret * (ch[0][p] && ch[1][p]);
}
}
using namespace Trie;
signed main() {
FASTIO
cin >> n;
rep(i, 1, n) cin >> a[i];
sort(a + 1, a + 1 + n);
rep(i, 1, n) ins(rt, i, 30);
cout << dfs(rt, 30);
return 0;
}
2025/2/5
P5437
一个完全图有
所以最小生成树的边权和的期望就可以用拉插来做,这个题比较板。
变形一下即可求出答案是
乱搞一下可得:
实际上这显然是没必要的,先将
注意不要写这个东西,因为最大可能有
const int N = 1e7 + 5;
rep(i, 1, N - 5) ...
点击查看
inline void init(int n) {
p[1] = 1;
rep(i, 2, n) {
if(!vis[i]) pr[++m] = i, p[i] = qkpow(i, k);
for(int j = 1; j <= m && 1LL * i * pr[j] <= n; ++j) {
vis[1LL * i * pr[j]] = 1;
p[1LL * i * pr[j]] = 1LL * p[i] * p[pr[j]] % mod;
if(i % pr[j] == 0) break;
}
}
rep(i, 2, n) p[i] = (p[i - 1] + p[i]) % mod;
}
inline void init_pv(int n, int nn) {
pre[0] = suf[0] = pre[n + 1] = suf[n + 1] = 1LL;
rep(i, 1, n) pre[i] = suf[i] = nn - i;
rep(i, 1, n) pre[i] = 1LL * pre[i - 1] * pre[i] % mod;
pre(i, n, 1) suf[i] = 1LL * suf[i + 1] * suf[i] % mod;
rep(i, 2, n) y[i] = ((1LL * y[i - 1] + p[i * 2 - 1] - p[i]) % mod + mod) % mod;
}
int Lagrange(int n) {
int ret = 0;
rep(i, 1, n) {
int p = 1LL * pre[i - 1] * suf[i + 1] % mod * inv[i - 1] % mod * inv[n - i] % mod;
if(n - i & 1LL) p = mod - p;
// cout << pre[i - 1] << ' ' << suf[i + 1] << ' ' << inv[i - 1] << ' ' << inv[n - i] << '\n';
ret = (ret + 1LL * p * y[i] % mod) % mod;
}
return ret;
}
2025/2/6
FFT 新知啊,由后到前写。
P3723
其实题目中一堆批话都是想让你求这个东西:
直接拆开得到
故求
发现除了
upd on 2025/2/10
ABC392G
哈哈场上通过将近 1000 人什么水平的题,具体见此不多评价了。
2025/2/7
NTT 新知啊。
CF1096G(*2400)
纽币的题,构造多项式
定义一个朴素 dp,
则答案为
然后你发现
然后就比较板了,现在开始写。
写的过程中比较顺利。
哦对了因为这个快速幂到最后多项式最多只有
点击查看
void sol() {
NTT(p, tot, 1);
rep(i, 0, tot) p[i] = qkpow(p[i], n / 2);
NTT(p, tot, -1);
int ret = 0;
rep(i, 0, tot) ret += p[i] * p[i], ret %= mod;
cout << ret << '\n';
}
完整 code。
2025/2/7
write on 2/6:明天 Rainybunny 要讲纽币的 dp,但多半是看题解,可能不会去听,应该是继续补 FFT/NTT 的题。
CF528D(*2500)
套路题,这种偏差不超过
for (int i = 0, lst = -1e9; i < n; i++) {
if (s[i] == c)
lst = i; // 找左边最近的当前字母 c.
if (i - lst <= k)
f.a[i] = 1; // 如果距离合法, 则设 1.
}
for (int i = n - 1, lst = 1e9; ~i; i--) {
if (s[i] == c)
lst = i; // 找右边最近的当前字母 c.
if (lst - i <= k)
f.a[i] = 1; // 如果距离合法, 则设 1.
}
写的也很顺利,完整 code。
P3321
2025/2/10
今日 crashed 讲 ds,听不懂一点但还是选了几道题做一下。
「雅礼集训 2017 Day1」市场
主要是有个操作是区间除(向下取整)不好整,考虑势能线段树,你发现每次除只会影响区间
void upd_div(int p, int ql, int qr, int k, int l = 1, int r = n) {
if(ql <= l && r <= qr) {
int px = mx[p] - floor(1.0 * mx[p] / k), py = mn[p] - floor(1.0 * mn[p] / k);
if(px == py) return s[p] -= (r - l + 1) * px, add[p] -= px, mn[p] -= px, mx[p] -= px, void();
}
down(p, l, r);
if(ql <= mid) upd_div(ls, ql, qr, k, l, mid);
if(qr > mid) upd_div(rs, ql, qr, k, mid + 1, r);
pushup(p);
}
青蛙题 Frog(rmscne)
破案了这道题是搬的 [Ynoi2005] rmscne
题目描述:先咕。
一个子段可以看作后缀的前缀,然后做扫描线,然后不会了看的第一篇题解,粘下认为比较重要的部分 code。
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 2e6 + 5;
int n, q, l, r, a[N], fa[N], lst[N], ans[N];
inline int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); }
void merge(int val) { if(lst[val]) fa[lst[val]] = lst[val] + 1; }
namespace SegmentTree {
int mn[N << 2], add[N << 2];
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid (l + r >> 1)
void pushup(int p) { mn[p] = min(mn[ls], mn[rs]); }
void down(int p, int l, int r) {
if(!add[p]) return;
add[rs] = mn[rs] = add[p], add[ls] = mn[ls] = add[p] + (r - mid);
// cout << '!' << add[ls] << ' ' << add[rs] << '\n';
add[p] = 0;
}
void build(int p, int l, int r) {
if(l == r) return mn[p] = 1e9, void();
build(ls, l, mid), build(rs, mid + 1, r), pushup(p);
}
void upd(int p, int ql, int qr, int &x, int l = 1, int r = n) {
// cout << '*' << x << '\n';
if(ql <= l && r <= qr) return x -= (r - l + 1), mn[p] = add[p] = x + 1, void();
down(p, l, r);
if(ql <= mid) upd(ls, ql, qr, x, l, mid);
if(qr > mid) upd(rs, ql, qr, x, mid + 1, r);
pushup(p);
}
int ask(int p, int ql, int qr, int l = 1, int r = n) {
if(ql <= l && r <= qr) return mn[p];
down(p, l, r);
int ret = 1e9;
if(ql <= mid) ret = min(ret, ask(ls, ql, qr, l, mid));
if(qr > mid) ret = min(ret, ask(rs, ql, qr, mid + 1, r));
return ret;
}
}
using namespace SegmentTree;
vector<PII> vec[N];
signed main() {
FASTIO
cin >> n, build(1, 1, n);
rep(i, 1, n) cin >> a[i], fa[i] = i;
cin >> q;
rep(i, 1, q) cin >> l >> r, vec[r].pb({l, i});
rep(i, 1, n) {
int pp = i - lst[a[i]];
// cout << '&' << p[a[i]] + 1 << ' ' << i << '\n';
upd(1, lst[a[i]] + 1, i, pp), merge(a[i]);
for(auto ed : vec[i]) ans[ed.se] = ask(1, ed.fi, get(ed.fi));
lst[a[i]] = i;
}
rep(i, 1, q) cout << ans[i] << '\n';
return 0;
}
2025/2/11
P3180
题意是给一颗仙人掌,
按套路建出圆方树后,由于
然后你会发现 tarjan 的过程可以直接合并答案,实现起来很简单。
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for (int i = j; i <= k; ++i)
#define pre(i, j, k) for (int i = j; i >= k; --i)
#define pb push_back
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 2e6 + 5;
const int M = 6e6 + 5;
int n, m, q, u, v, op, mx, ans[N], w[N];
int head[N], nxt[N], to[N], tt;
void add(int u, int v) {
to[++tt] = v, nxt[tt] = head[u], head[u] = tt;
}
namespace SegmentTree {
int ls[M], rs[M], odd[M], even[M], rt[N];
#define mid (l + r >> 1)
int cnt = 0;
void pushup(int p) {
odd[p] = even[p] = 0;
if(ls[p]) odd[p] += odd[ls[p]], even[p] += even[ls[p]];
if(rs[p]) odd[p] += odd[rs[p]], even[p] += even[rs[p]];
}
void upd(int &p, int l, int r, int k) {
if(!p) p = ++cnt;
if(l == r) return odd[p] = 1, void();
if(k <= mid) upd(ls[p], l, mid, k);
else upd(rs[p], mid + 1, r, k);
pushup(p);
}
int merge(int p, int q, int l, int r) {
if(!p || !q) return p | q;
if(l == r) {
if(even[p] && even[q]) return p;
if(odd[p] && even[q]) return p;
if(even[p] && odd[q]) return q;
odd[p] = 0, even[p] = 1;
return p;
}
ls[p] = merge(ls[p], ls[q], l, mid), rs[p] = merge(rs[p], rs[q], mid + 1, r);
pushup(p);
return p;
}
int ask(int p, int l, int r, int ql, int qr, int op) {
// cout << '!' << l << ' ' << r << '\n';
if(!p || ql > r || l > qr) return 0;
if(ql <= l && r <= qr) return (op ? odd[p] : even[p]);
return ask(ls[p], l, mid, ql, qr, op) + ask(rs[p], mid + 1, r, ql, qr, op);
}
}
using namespace SegmentTree;
int dfn[N], low[N], stk[N], top, T, S;
struct Query {
int x, id, type;
};
vector<Query> vec[N];
void tarjan(int x) {
dfn[x] = low[x] = ++T;
stk[++top] = x;
upd(rt[x], 0, mx, w[x]);
for(int i = head[x]; i; i = nxt[i]) {
int y = to[i];
if(!dfn[y]) {
tarjan(y), low[x] = min(low[x], low[y]);
if(dfn[x] == low[y]) {
int z = 0;
do {
z = stk[top--];
// cout << '*' << rt[x] << ' ' << rt[z] << '\n';
merge(rt[x], rt[z], 0, mx);
} while(y != z);
}
}
else low[x] = min(low[x], dfn[y]);
}
for(auto ed : vec[x]) ans[ed.id] = ask(rt[x], 0, mx, 0, min(ed.x, mx), ed.type);
}
signed main() {
FASTIO
cin >> n >> m;
rep(i, 1, n) cin >> w[i], mx = max(mx, w[i]);
rep(i, 1, m) cin >> u >> v, add(u, v), add(v, u);
cin >> q;
rep(i, 1, q) cin >> op >> u >> v, vec[u].pb({v, i, op});
tarjan(1);
rep(i, 1, q) cout << ans[i] << '\n';
return 0;
}
本文作者:Iron_Spade
本文链接:https://www.cnblogs.com/walrus908424/p/18708105
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术