题解:P3023 [USACO11OPEN] Soldering G

· · 题解

提供一篇目前没被 hack 的题解

考虑 O(n^2) 的做法

有 $2$ 种转移,如图,红色和黑色表示将黑色线接在红色线的中间位置。 ![](https://cdn.luogu.com.cn/upload/image_hosting/8jeuf2i3.png) 设当前节点为 $x$,儿子为 $y$。 1. 选一个儿子节点,将其他儿子节点连在其上,计算其他儿子的贡献。 先对每个儿子节点统计最小贡献: $$mn_y \gets \min\{f_{y,j}+(j+1)^2\}$$ 再计算总的贡献: $$res\gets\sum _ {y\in son{x}} mn_y$$ 最后进行转移: $$f_{x,j}\gets\min\{f_{y,j-1}+res-mn_y,f_{x,j}\}$$ ![](https://cdn.luogu.com.cn/upload/image_hosting/lsitfzlh.png) 3. 选两个儿子节点连在一起,计算所有的贡献。 枚举儿子 $i$ 和 $j$,有转移: $$f_{x,0}\gets \min \{ f_{x,0},f_{i,s1}+f_{j,s2}+(s1+s2+2)^2+res-mn_i-mn_j \}$$ #### 考虑优化 去掉多余的状态。 对于 $f_{x,i}$ 和 $f_{x,j}$,当 $i>j$ 且 $f_{x,i}+i^2 \ge f_{y,j}+j^2$ 时,显然 $f_{x,i}$ 无意义,可以删去,最后用 `vector` 存 $f_{x}$ 即可通过此题。此时已经可以通过官方数据了,但会被菊花图卡。瓶颈在于第二种转移,发现对于儿子节点超过两个的相同状态对此转移无意义,用 `map` 去重。 #### 代码 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=5e4+5; int n; vector<pair<int,int> >f[N]; int mn[N]; void work(vector<pair<int,int> >&p){ sort(p.begin(),p.end()); vector<pair<int,int> >tmp; for(auto i:p){ if(tmp.empty()||i.second+i.first*i.first<tmp.back().second+tmp.back().first*tmp.back().first)tmp.push_back(i); } p=tmp; } vector<int>e[N]; struct node{ int first,second,id; }; void dfs(int x,int fa){ for(int y:e[x]){ if(y==fa)continue; dfs(y,x); } int res=0; for(int y:e[x]){ if(y==fa)continue; mn[y]=1e18; for(auto i:f[y]){ int l=i.first,s=i.second; l++; mn[y]=min(s+l*l,mn[y]); } res+=mn[y]; } for(int y:e[x]){ if(y==fa)continue; for(auto i:f[y]){ int l=i.first,s=i.second; f[x].emplace_back(l+1,res-mn[y]+i.second); } } int ad=1e18; map<int,map<unsigned long long ,map<long long,int> > >mp; vector<node >tmp; for(int y:e[x]){ for(auto i:f[y]){ mp[i.first][i.second][mn[y]]++; if(mp[i.first][i.second][mn[y]]<=2)tmp.push_back({i.first,i.second,y}); } } for(auto i:tmp){ for(auto j:tmp){ if(i.id==j.id)continue; int tres=res-mn[i.id]-mn[j.id]; ad=min(ad,tres+i.second+j.second+(i.first+j.first+2)*(i.first+j.first+2)); } } f[x].emplace_back(0 , ad ); if(e[x].size()==1){ if(e[x][0]==fa){ f[x].emplace_back(0,0); } else { for(auto i:f[e[x][0]]){ f[x].emplace_back(0,i.second+(i.first+1)*(i.first+1)); } } } for(int y:e[x]){ if(y!=fa){ f[y].clear(); f[y].shrink_to_fit(); } } work(f[x]); } signed main (){ cin>>n; for(int i=1;i<n;i++){ int x,y; cin>>x>>y; e[x].push_back(y); e[y].push_back(x); } dfs(1,0); if(f[1].empty()){ cout<<"E"; //调试时防止程序崩溃 exit(0); } cout<<f[1][0].second; return 0; } ```