CF1801C 做题笔记
一道需要挖掘一些性质的 dpt,居然独立想出来了。
本蒟蒻太菜了只会树状数组的做法,单调栈不会。
先考虑只管对答案有贡献的音乐,这当然是正确的,因为我们可以把对答案没有贡献的音乐放到最后。
对于每一首乐曲,我们也能对它进行一个简单的处理来模拟听的过程,维护一个值
假设每个音乐的好听程度为其中最美妙的片段。
处理后有一个可以感性理解的结论:无论当前听过的最好听的片段是什么,听了一首乐曲,能够使答案增加的一定是存入数组中的片段。
证明考虑反证,假设当前听过最好听的片段好听值为
再来想,有答案贡献的音乐放在一起,每个音乐的好听程度一定是递增的。
做法于是很显然了,先将所有音乐按照好听程度排序,设
上述为
考虑对于每一个乐曲的转移改为枚举这个乐曲中的每一个没被忽略的片段,然后去找前面的某个乐曲
很绕口,读不懂多读几遍,然后这是个单点修改求前缀最值可以用树状数组优化到
代码:
#include <bits/stdc++.h> #define int long long #define For(i, a, b) for (int i = (a); i <= (b); i ++) #define foR(i, a, b) for (int i = (a); i >= (b); i --) using namespace std; int n, x, cnt; int c[200005], dp[200005], idx[200005]; vector <int> a[200005]; vector <int> v[200005]; void add (int x, int y) {for (; x <= 200000; x += x & -x) c[x] = max (c[x], y);} int query (int x) {return (x == 0 ? 0 : max (query (x - (x & -x) ), c[x]) );} void clear (int x) {for (; x <= 200000; x += x & -x) c[x] = 0;} set <int> s; void solve () { s.clear (); scanf ("%lld", &n); For (i, 1, n) { scanf ("%lld", &cnt); int last = 0; while (cnt --) { scanf ("%lld", &x); if (x > last) { a[i].push_back (x); last = x; } } s.insert (last); v[last].push_back (i); } cnt = 0; for (int i : s) for (int j : v[i]) idx[++ cnt] = j; int ans = 0; For (i, 1, n) { for (int j = 0; j < a[idx[i] ].size (); j ++) dp[i] = max (dp[i], query (a[idx[i] ][j] - 1) + (long long) (a[idx[i] ].size () ) - j); add (a[idx[i] ].back (), dp[i]); ans = max (ans, dp[i]); } cout << ans; For (i, 1, n) { clear (a[i].back () ); v[a[i].back ()].clear (); a[i].clear (); dp[i] = 0; } } signed main () { int _ = 1; cin >> _; while (_ --) { solve (); cout << '\n'; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异