多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

2026-10-07 hetao1733837 的刷题记录

2026-10-07 hetao1733837 的刷题记录 CF1187E Tree Painting原题链接E. Tree Painting题意给你一棵树初始所有节点为白色。每次操作选择一个与已经染成黑色的点相邻的点第一次任选一个染黑获得的权值是选择点未所在连通块未被染黑的连通块的大小。求最大的权值。分析这个真的换根了吗哦那么理论上就是我们需要知道最开始的点是哪个。那么我们设d p u dp_{u}dpu​表示我们第一次染u uu的最大值。我们发现每次染色都会使拿个连通块大小− 1 -1−1。我为什么感觉这个题可以直接贪心静静地思考一下。不是我真觉得这个是个贪……转移是贪的。我们发现由于这是一个树所以我们每次的选择都是相当于这个连通块的大小− 1 -1−1所以构成了一个等差数列这里是错误的。我们需要明确的就是每次的每个节点的子树大小……我在说什么……所以换根的意义就是这个我们需要更新大小。然后你做完了。天啊这个题解交上去能过审握持……怎么写代码呢我们明确一下流程build graphdfschange rootget maxprint题解我们设d p u dp_{u}dpu​表示最开始选u uu的收益如果说每次都单独求那么复杂度是O ( n 2 ) O(n^2)O(n2)的显然不能过。那么由于每个点都会作为“根节点”不妨考虑换根DP。我们发现每个点的权值就是∑ v ∈ s o n u s z v \sum\limits_{v\in son_u}^{}{sz_{v}}v∈sonu​∑​szv​那么我们可以进行非常轻易的转移。我们发现在换根的时候对于v vv的子树他的所有点的贡献都会− 1 -1−1因为我们选择了v vv而对于v vv子树之外的点他们的连通块都更大了因为之前的u f a v ufa_vufav​不选了所以剩下的的都 1 11所以我们有了转移方程d p v d p u ( n − s z v ) − s z v dp_{v} dp_{u}(n-sz_v)-sz_vdpv​dpu​(n−szv​)−szv​那么你做完了正解#includebits/stdc.h#defineintlonglongusingnamespacestd;constintN200005;intn;vectorinte[N];intsz[N],dp[N];intans;voiddfs1(intu,intfa){sz[u]1;dp[u]0;for(intv:e[u]){if(vfa)continue;dfs1(v,u);sz[u]sz[v];dp[u]dp[v];}dp[u]sz[u];}voiddfs2(intu,intfa){ansmax(ans,dp[u]);for(intv:e[u]){if(vfa)continue;dp[v]dp[u]n-2*sz[v];dfs2(v,u);}}signedmain(){ios::sync_with_stdio(0);cin.tie(0);cinn;for(inti1,u,v;in;i){cinuv;e[u].push_back(v);e[v].push_back(u);}dfs1(1,0);ansdp[1];dfs2(1,0);coutans;return0;}但是问题来了为什么l z lzlz用我的代码造的数据我第一发RE了LGP10962 Computer原题链接Computer分析这个板完了别急似乎并非啊……难道说我要记录一个极长链和一个次长链然后DP吗好像还真是……哦不不不这无疑是令人难绷得……难道说我在直径上吗喔……居然是真的那这个不止绿啊……这个题竟然有两个方法方法一我们知道在一个点到树上的最远距离一定是直径的端点那么这个就可以直接做了但是呢这里有一点比较复杂就是说因为这个树是带权的所以说我们还需要树上差分 LCA之类的东西来求距离不过复杂度倒是可以接受……其实也不用直接dfs两边预处理就做完了方法二我们跑二遍dfs记录up和down表示向上和向下的最长长度向下还要再记录一个次长。怎么感觉本质上和直径的那么像呢这个并不好玩……开到真的好题了正解//Method 1#includebits/stdc.h#defineintlonglongusingnamespacestd;constintN100005;intn;vectorpairint,inte[N];intd1[N],d2[N];ints,t;intmx,pos;voiddfs1(intu,intfa,intdis){d1[u]dis;if(dismx){mxdis;posu;}for(autotmp:e[u]){if(tmp.firstfa)continue;dfs1(tmp.first,u,distmp.second);}}voiddfs2(intu,intfa,intdis){d2[u]dis;if(dismx){mxdis;posu;}for(autotmp:e[u]){if(tmp.firstfa)continue;dfs2(tmp.first,u,distmp.second);}}voidinit(){for(inti1;in;i){e[i].clear();}}signedmain(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);while(cinn){init();for(inti2,v,w;in;i){cinvw;e[i].push_back({v,w});e[v].push_back({i,w});}mx0xc0c0c0c0c0c0c0c0;dfs1(1,0,0);spos;mx0xc0c0c0c0c0c0c0c0;dfs1(s,0,0);tpos;mx0xc0c0c0c0c0c0c0c0;dfs2(t,0,0);for(inti1;in;i){coutmax(d1[i],d2[i])\n;}}}\\Method2#includebits/stdc.h#defineintlonglongusingnamespacestd;constintN10005;intn;vectorpairint,inte[N];intd[N],dd[N];intdp[N];intson[N];voiddfs1(intu,intfa){for(autotmp:e[u]){if(tmp.firstfa)continue;dfs1(tmp.first,u);if(d[u]d[tmp.first]tmp.second){dd[u]d[u];d[u]d[tmp.first]tmp.second;son[u]tmp.first;}elseif(dd[u]d[tmp.first]tmp.second){dd[u]d[tmp.first]tmp.second;}}}voiddfs2(intu,intfa){for(autotmp:e[u]){if(tmp.firstfa)continue;if(son[u]!tmp.first)dp[tmp.first]max(d[u],dp[u])tmp.second;elsedp[tmp.first]max(dd[u],dp[u])tmp.second;dfs2(tmp.first,u);}}voidinit(){memset(dp,0,sizeof(dp));memset(d,0,sizeof(d));memset(dd,0,sizeof(dd));for(inti1;in;i){e[i].clear();}}signedmain(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);while(cinn){init();for(inti2,v,w;in;i){cinvw;e[i].push_back({v,w});e[v].push_back({i,w});}dfs1(1,0);dfs2(1,0);for(inti1;in;i){coutmax(d[i],dp[i])\n;}}}AT_arc231_d [ARC231D] Choose Your Role原题链接D - Choose Your Role分析我们只需要维护这个对称性就可以了……为什么呢因为后手并不自由这是什么理由呢也就是相当于下模仿棋……所以后手必胜……这都是啥啊翻译了一下官方题解考虑给石子染色。假设堆 (i) 对于颜色 (1,2,\cdots,N) 中除颜色 (i) 外的每种颜色都恰好有一颗该颜色的石子也就是共有 (N-1) 颗石子。在初始状态以下对称性成立对于 (i \ne j)堆 (i) 中是否有颜色 (j) 的石子与堆 (j) 中是否有颜色 (i) 的石子相同。当先手从对称性成立的状态走一步后对称性不再成立。作为后手我们的目标是让自己每走一步之后对称性都重新成立。假设先手从堆 (i) 中移除了颜色为 (c_1,c_2,\cdots,c_j) 的石子。如果在先手移动之前上述对称性保持成立那么我们可以从堆 (c_1,c_2,\cdots,c_j) 中各移除一颗颜色为 (i) 的石子。并且在这步之后对称性再次成立。在最终没有石子剩余的状态下对称性成立。因此通过按上述方式移动后手可以获胜。我们可以直接实现这个策略。通过用集合或类似数据结构来管理每堆石子的颜色可以例如在 (O(N^2 \log N)) 时间内解决。为啥我的过不了就是你发现n × ( n − 1 ) n\times (n-1)n×(n−1)必然是一个偶数而每次先手最多取n − 1 n-1n−1我们还可以在剩下的取这么多所以就解决了维护对称性显然是正确的。正解#includeiostream#includeset#includevectorusingnamespacestd;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);intn,k;cinnk;coutSecondendl;vectorsetintstone(n);for(inti0;in;i){for(intj0;jn;j){if(ij)continue;stone[i].insert(j);}}while(true){ints,t;cinst;if(s0){return0;}s--;couttendl;for(inti0;it;i){intc*stone[s].begin();stone[s].erase(c);stone[c].erase(s);coutc1 ;}coutendl;}}难道交互库不认识\n
返回列表