解题:八省联考2018 林克卡特树

题面

DP凸优化

题目并不难

先转化问题,显然k=0的时候我们都知道是求直径,然后k=1就是选两条点不相交的链拼起来,很容易推出题目就是要我们在树上选$k+1$条点不相交的链

事实上你直接按照边不相交做,取k+1次直径都可以得到50pts的好成绩,我佛了(不要问我怎么知道的

这个东西是可以DP的(稍微有点麻烦):设$dp[i][j][0/1/2]$表示以$i$为根的子树里选出j条链,这时i的度数为0/1/2的最优解。度数为零表示i是单独一个点,度数为1表示是链的端点,度数为2就是链中间的一个点

然后转移就是拼来拼去,看代码吧

60pts暴力DP↓

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=300005,K=105;
 6 int n,k,t1,t2,t3,cnt;
 7 long long dp[N][K][3];
 8 int p[N],noww[2*N],goal[2*N],val[2*N],siz[N];
 9 void Maxi(long long &x,long long y)
10 {
11     if(x<y) x=y;
12 }
13 void Link(int f,int t,int v)
14 {
15     noww[++cnt]=p[f],p[f]=cnt;
16     goal[cnt]=t,val[cnt]=v;
17     noww[++cnt]=p[t],p[t]=cnt;
18     goal[cnt]=f,val[cnt]=v;
19 }
20 void DFS(int nde,int fth)
21 {
22     siz[nde]=1;
23     dp[nde][0][0]=dp[nde][1][1]=dp[nde][1][2]=0;
24     for(int i=p[nde];i;i=noww[i])
25         if(goal[i]!=fth)
26         {
27             int g=goal[i]; DFS(g,nde);
28             for(int j=min(siz[nde],k);~j;j--)
29                 for(int h=min(siz[goal[i]],k-j+1);~h;h--)
30                 {
31                     for(int l=0;l<=2;l++)
32                         for(int f=0;f<=2;f++)
33                             Maxi(dp[nde][j+h][l],dp[nde][j][l]+dp[g][h][f]);
34                     if(j+h<k) Maxi(dp[nde][j+h+1][1],dp[nde][j][0]+dp[g][h][0]+val[i]);
35                     Maxi(dp[nde][j+h][1],dp[nde][j][0]+dp[g][h][1]+val[i]);
36                     Maxi(dp[nde][j+h][2],dp[nde][j][1]+dp[g][h][0]+val[i]);
37                     if(j&&h) Maxi(dp[nde][j+h-1][2],dp[nde][j][1]+dp[g][h][1]+val[i]);
38                 }
39             siz[nde]+=siz[goal[i]];
40         }
41 }
42 int main()
43 {
44     scanf("%d%d",&n,&k),k++;
45     for(int i=1;i<n;i++)
46     {
47         scanf("%d%d%d",&t1,&t2,&t3);
48         Link(t1,t2,t3);
49     }
50     memset(dp,0xc0,sizeof dp),DFS(1,0);
51     printf("%lld",max(dp[1][k][0],max(dp[1][k][1],dp[1][k][2])));
52     return 0;
53 }

考虑优化

官方的题解是这么写的:

emmmm......

好吧我们不管具体过程,先假装我们发现了这个规律。差分后递减,说明这是个上凸函数(以选取的链数为x轴,最优解为y轴)。这种DP有个套路的优化方法叫做凸优化:二分斜率,然后我们强制选取物品时额外付出斜率的代价(这里是选链)。这时套用原来那个DP(把它当成一个黑箱,输入直线输出切点),相当于不限制数目地选取。最后得到一个最优情况下选出来的数目,根据这个数目调整二分上下界即可。

为什么这是对的?

数形结合地考虑这个问题,减去斜率相当于把

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=600005;
 6 int p[N],noww[N],goal[N],val[N];
 7 int n,k,t1,t2,t3,cnt; long long del;
 8 struct a
 9 {
10     int cho;
11     long long sum;
12 }dp[N][3];
13 a operator + (a x,a y)
14 {
15     return (a){x.cho+y.cho,x.sum+y.sum};
16 }
17 bool operator < (a x,a y)
18 {
19     if(x.sum^y.sum) return x.sum<y.sum;
20     return x.cho<y.cho;
21 }
22 void Maxi(a &x,a y)
23 {
24     if(x<y) x=y;
25 }
26 void Link(int f,int t,int v)
27 {
28     noww[++cnt]=p[f],p[f]=cnt;
29     goal[cnt]=t,val[cnt]=v;
30     noww[++cnt]=p[t],p[t]=cnt;
31     goal[cnt]=f,val[cnt]=v;
32 }
33 void DFS(int nde,int fth)
34 {
35     dp[nde][2]={1,-del};
36     for(int i=p[nde];i;i=noww[i])
37         if(goal[i]!=fth)
38         {
39             int g=goal[i]; DFS(g,nde);
40             dp[nde][2]=max(dp[nde][2]+dp[g][0],dp[nde][1]+dp[g][1]+(a){1,val[i]-del});
41             dp[nde][1]=max(dp[nde][1]+dp[g][0],dp[nde][0]+dp[g][1]+(a){0,val[i]});
42             dp[nde][0]=dp[nde][0]+dp[g][0];
43         }
44     Maxi(dp[nde][0],dp[nde][1]+(a){1,-del});
45     Maxi(dp[nde][0],dp[nde][2]);
46 }
47 int Calc(long long x)
48 {
49     del=x;
50     for(int i=1;i<=n;i++)
51         dp[i][0]=dp[i][1]=(a){0,0}; DFS(1,0);
52     return dp[1][0].cho;
53 }
54 int main()
55 {
56     scanf("%d%d",&n,&k),k++;
57     for(int i=1;i<n;i++)
58     {
59         scanf("%d%d%d",&t1,&t2,&t3);
60         Link(t1,t2,t3);
61     }
62     long long l=-1e12,r=1e12,ans=0;
63     while(l<=r)
64     {
65         long long mid=(l+r)>>1;
66         (Calc(mid)>=k)?l=mid+1,ans=mid:r=mid-1;
67     }
68     Calc(ans),printf("%lld",dp[1][0].sum+ans*k);
69     return 0;
70 }

原文地址:https://www.cnblogs.com/ydnhaha/p/10436329.html

时间: 2024-07-30 11:17:47

解题:八省联考2018 林克卡特树的相关文章

[八省联考2018]林克卡特树lct

#include<bits/stdc++.h> #define RG register #define IL inline #define _ 500005 #define INF 1e18 #define ll long long using namespace std; IL ll gi(){ RG ll data = 0 , m = 1; RG char ch = 0; while(ch != '-' && (ch<'0' || ch > '9')) ch =

[八省联考2018]林克卡特树

题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(Cut)树上的 恰好K 条边,然后再连接 K

P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

$ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(

[九省联考2018]林克卡特树(DP+wqs二分)

对于k=0和k=1的点,可以直接求树的直径. 然后对于60分,有一个重要的转化:就是求在树中找出k+1条点不相交的链后的最大连续边权和. 这个DP就好.$O(nk^2)$ 然后我们完全不可以想到,将best[k](选择k条链的答案)打表输出,更不可能然后作差分,发现得到的数组是递减的. 这说明:best[k]是一个上凸包. 于是我们可以二分一个斜率去切这个凸包(类似导数),根据切点横坐标与k的大小旋转直线(改变斜率). 考虑给你一个直线斜率k,怎么找到它和凸包的切点.实际上就相当于将这个凸函数减

【BZOJ5251】【八省联考2018】劈配(网络流,二分答案)

[BZOJ5251][八省联考2018]劈配(网络流,二分答案) 题面 洛谷 BZOJ Description 一年一度的综艺节目<中国新代码>又开始了. Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayid顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的: 总共n名参赛选手(编号从1至n)每人写出一份代码并介绍自己的梦想.接着由所有导师对这些选手进行排名. 为了避免后续的麻烦,规定不存在排名并列的情况. 同

[八省联考2018] 劈配

题目背景 一年一度的综艺节目<中国新代码>又开始了.Zayid 从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayid 顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的: 总共n 名参赛选手(编号从1 至n)每人写出一份代码并介绍自己的梦想.接着 由所有导师对这些选手进行排名.为了避免后续的麻烦,规定不存在排名并列的情况. 同时,每名选手都将独立地填写一份志愿表,来对总共 m 位导师(编号从 1 至 m)作出评价.志愿表

洛谷P4382 [八省联考2018]劈配(网络流,二分答案)

洛谷题目传送门 说不定比官方sol里的某理论最优算法还优秀一点? Orz良心出题人,暴力有70分2333 思路分析 正解的思路很巧妙,其实我并不觉得这是个正儿八经的网络流或者二分图匹配的题目,主要还是个思维+建图模型+乱搞...... \(C=1\)时我们就可以对于每个人直接匹配而不会影响到后面的选择了.但是\(C>1\)的话,可能某一个人可以选多个导师,当他随便选了其中一个以后,可能影响到后面某个人使其选不到本来的最优解.而此时后面那个人就要让前面那个人改变决策,做出反悔. 这时候有没有想到网

【BZOJ5248】【九省联考2018】一双木棋(搜索,哈希)

[BZOJ5248][九省联考2018]一双木棋(搜索,哈希) 题面 BZOJ Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij.Bij.在 游戏结束后,菲菲和牛牛会分别计算自己

[luogu] P4364 [九省联考2018]IIIDX(贪心)

P4364 [九省联考2018]IIIDX 题目背景 Osu 听过没?那是Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI 内工作,离他的梦想也越来越近了. 这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻.同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高. 题目描述 这一天,Konano 接到了一个任务