CF1646D题解
傳送門
首先我們可以發(fā)現(xiàn),當(dāng) n≥2n \geq 2n≥2 的時(shí)候,任意兩個(gè)相鄰的點(diǎn)不可能同為好節(jié)點(diǎn)(((因?yàn)橐欢ㄓ衅渌?jié)點(diǎn)破壞他們兩個(gè)相等)))。當(dāng) n=2n = 2n=2 的時(shí)候,特判掉即可。
我們考慮如何進(jìn)行樹形 DPDPDP,設(shè) f[u][1/0]f[u][1/0]f[u][1/0] 表示在以 uuu 為根的子樹中,uuu 是好節(jié)點(diǎn) (f[u][1])(f[u][1])(f[u][1]) 或者不是好節(jié)點(diǎn) (f[u][0])(f[u][0])(f[u][0]) 的時(shí)候,最多能有多少個(gè)好節(jié)點(diǎn)。在轉(zhuǎn)移的過程中 ,因?yàn)橛猩鲜龅男再|(zhì),所以當(dāng)欽定 uuu 為好節(jié)點(diǎn)時(shí),它的孩子 vvv 只能不是好節(jié)點(diǎn),當(dāng) uuu 不是好節(jié)點(diǎn)時(shí),它的孩子 vvv 可以是好節(jié)點(diǎn),也可以不是好節(jié)點(diǎn)。
我們將 DPDPDP 的數(shù)組定義一個(gè) pairpairpair,firstfirstfirst 表示好節(jié)點(diǎn)的數(shù)目,secondsecondsecond 表示在這個(gè)數(shù)目下所需要的和。轉(zhuǎn)移的時(shí)候分別對(duì)于 firstfirstfirst 和 secondsecondsecond 轉(zhuǎn)移,當(dāng) firstfirstfirst 相同的時(shí)候,要轉(zhuǎn)移 secondsecondsecond 小的。我們貪心的想,最后的方案一定是,所有不是好節(jié)點(diǎn)的值是 111,所有是好節(jié)點(diǎn)的值是 deg[u]deg[u]deg[u]。
具體轉(zhuǎn)移如下:
{f[u][1]=∑f[v][0]+1f[u][0]=max?(f[v][0],f[v][1])\begin{cases} f[u][1] = \sum{f[v][0]}+1\\ f[u][0] = \max(f[v][0],f[v][1]) \end{cases}{f[u][1]=∑f[v][0]+1f[u][0]=max(f[v][0],f[v][1])?
最后就是輸出方案了,先將根節(jié)點(diǎn)(((規(guī)定為1)1)1)是好節(jié)點(diǎn)還是不是好節(jié)點(diǎn)最優(yōu),然后往下 dfsdfsdfs,如果這個(gè)節(jié)點(diǎn)是好節(jié)點(diǎn),那么孩子節(jié)點(diǎn)就都不能是好節(jié)點(diǎn),一直把整棵樹遍歷完,最后輸出答案即可。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define re register #define rep(a,b,c) for(re int a(b) ; a<=c ; ++a) #define drep(a,b,c) for(re int a(b) ; a>=c ; --a) using namespace std; inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}return x*f; } const int M = 4e5+10; typedef pair<int,int> pii; int n,cnt; int head[M],du[M],ans[M]; pii f[M][2]; struct edge{int to,nxt; }e[M]; inline void add(int u,int v){e[++cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt; } inline bool check(pii x,pii y){if(x.first != y.first) return x.first > y.first;return x.second < y.second; } inline void dfs(int u,int fa){f[u][1] = make_pair(1,du[u]);f[u][0] = make_pair(0,1);for(re int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to;if(v == fa) continue;dfs(v,u);f[u][1].first += f[v][0].first;f[u][1].second += f[v][0].second;if(check(f[v][0],f[v][1])) f[u][0].first += f[v][0].first,f[u][0].second += f[v][0].second;else f[u][0].first += f[v][1].first,f[u][0].second += f[v][1].second;} } inline void print(int u,int fa,int zt){if(zt) ans[u] = du[u];else ans[u] = 1;for(re int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to;if(v == fa) continue;if(zt) print(v,u,0);else{if(check(f[v][0],f[v][1])) print(v,u,0);else print(v,u,1);}} } signed main(){n = read();rep(i,1,n-1){int u = read(),v = read();add(u,v),add(v,u);du[u]++,du[v]++;}if(n == 2){printf("2 2\n");printf("1 1\n");return 0;}dfs(1,0);if(check(f[1][0],f[1][1])){printf("%d %d\n",f[1][0].first,f[1][0].second);print(1,0,0);}else{printf("%d %d\n",f[1][1].first,f[1][1].second);print(1,0,1);}rep(i,1,n) printf("%d ",ans[i]);return 0; }總結(jié)
- 上一篇: springboot layuiAdmi
- 下一篇: 2023美赛基础知识以及如何入门