【前言】
这是一道思维题,本质是贪心,没什么代码量。
偶尔抖机灵抖出来的题目。
【暴力】
O(n!)枚举,我的数据最小的n是100.
很遗憾。
当然可能有稍微优秀一点点的暴力做法。
【正解】
目标是最大化答案,答案最大的情况就是每条边被选正好一次,因为无论如何改变排列p[],p[i]和p[i+1]的路径的并集都会是整棵树,你需要到达每一个点,因此每条边都需要经过至少一次。
尝试证明这个答案可以达到,假设初始所有点都未放入p[]中,且w最大的边为x,若计算一次w[x],需要将u[x]和v[x]放在排列p[]的相邻位置,则将u[x]和v[x]放入p[]中,位置不管,但必定相邻,再看次大边,若次大边的某一段已经在p中,则随意将另一点放入已在p[]中随便一个点的相邻侧,否则将两端点都放入,具***置先不管,但这两个点相邻...当进行到某条边,就会有如下情况:
1、当这条边两个端点都未放入p[]中,将这两个点放入p[]中,位置不管,但要求相邻;
2、当这条边某个端点已经在p[]中,另一端点尝试放在这个端点的相邻侧,否则放在与它相连的一系列点的相邻侧,这个位置必然存在,因为重复这个过程的话,新加入节点必然成为新的末端,可以接纳往后的节点,且已在p[]中保持相邻位置的点,其间边的边权必然也是大于往前边权的;
3、若两个点都在,则拼接以此两点为拼接口,将两段相连的点拼接成一段;
重复上述过程,你会发现,最终n个点都加入了p[],且每次加入都会产生一次拼接,n-1次拼接之后,n个点就会变成有序的一段,p[]也就被构造出来了。
对于任何树,以上构造方法都可行,因此答案就是边权的和。
参考代码(过于简单,感觉甚至没必要贴这个代码):
class Solution { public: /** * * @param n int整型 * @param seed1 long长整型 * @param seed2 long长整型 * @param seed3 long长整型 * @return long长整型 */ long long work(int n, long long seed1, long long seed2, long long seed3) { // write code here long long ans=0,seed4; for (int i=1;i<n;i++) { seed4=(seed1+seed2)%998244353*seed3%998244353; ans=ans+seed2*seed3%12131415; seed3=seed2; seed2=seed1; seed1=seed4; } return ans; } };