拿小号打了这场,然而做到这里时少看了条件,最后 10min 才发现,没有 AK,身败名裂……

赛后看就是 sb 题……

(好像这题也不值 2500 吧?)

首先注意到一条很重要的条件:对于每棵树,都存在一种 DFS 序使得叶子被访问到的顺序就是与它相连的用电器的编号。

这说明,对于每棵树的任意子树,里面所有叶子对应的用电器的编号是连续的。

既然连续就能方便 DP 了。

正着做不好设计状态。反过来,求最少能保留多少条边。

那么就是每个用电器对应的叶子到根上的边都要选。没有限制的全部能删掉。

然后由于用电器对应的叶子的 DFS 序递增,所以对于一个用电器集合 \(\{S\}(|S|\ge 2)\),如果这里面每个用电器都和同一个根相连,那么 \(S\) 的花费 \(cost_S\) 是 \(cost_{S-x}+dep_x-dep_{lca(x,y)}\),其中 \(x\) 是 \(S\) 中编号最大的用电器,\(y\) 是 \(S\) 中编号第二大的用电器。

上 DP。

先记 \(f_{i,j,0}(i<j)\) 表示第 \(i\) 个用电器和第 \(j\) 个用电器如果都选第 \(0\) 棵树时,\(dep_{x_i}-dep_{lca(x_i,x_j)}\) 的值。\(f_{i,j,1}\) 同理。

再记 \(fpre_{i,j,0}(i\le j)\) 表示第 \(i\) 个用电器到第 \(j\) 个用电器都选在第 \(0\) 棵树时的总花费。大概是个类似前缀和的东西。\(fpre_{i,j,1}\) 同理。

再记 \(dp_{i,j,0}(i>j)\) 表示只考虑前 \(i\) 个用电器,第 \(j\) 到第 \(i\) 个用电器都选在第 \(0\) 棵树,且第 \(j-1\) 个用电器选在第 \(1\) 棵树的最小花费。\(dp_{i,j,1}\) 同理。

转移,枚举第 \(k\) 到第 \(j-1\) 个用电器选在第 \(1\) 棵树(且 \(k-1\) 选在第 \(0\) 棵树)。\(dp_{i,j,0}=fpre_{j,i,0}+\min(dp_{j-1,k,1}+f_{k-1,j,0}-(dep_{x_j}[k\ne 1]))\)。

解释一下。

\(fpre_{j,i,0}\) 就是 \(j\) 到 \(i\) 的花费。

\(dp_{j-1,k,1}\) 就是 \(k\) 到 \(j-1\) 的最小花费。

\(f_{k-1,j,0}\) 是因为:考虑从小到大加入 \(j\) 到 \(i\),按上文说的最大编号和次大编号计算贡献。所以加入 \(j\) 时,就会比原来的花费多 \(dep_{x_j}-dep_{lca(x_j,x_{k-1})}\),也就是 \(f_{k-1,j,0}\)。

当 \(k\ne 1\) 时,由于 \(fpre\) 中算的贡献中 \(j\) 是要自力更生的,但是实际上此时 \(k-1\) 可以给 \(j\) 一些已经用过的边(这个费用就是上面的 \(f_{k-1,j,0}\))。所以要把 \(dep_{x_j}\) 减掉。

这是个 \(O(n^3)\) 做法。

优化也很显然。设 \(mn_{i,0}=\min(dp_{i-1,j,1}+f_{j-1,i,0}-(dep_{x_i}[j\ne 1]))\)。\(mn_{i,1}\) 同理。

那么有 \(dp_{i,j,0}=fpre_{j,i,0}+mn_{j,0}\)。

时间复杂度 \(O(n^2)\)。

传说有 \(O(n)\) 做法,但我不会……

代码中略微有一点不一样,稍微注意。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. typedef pair<int,int> PII;
  5. const int maxn=2222;
  6. #define MP make_pair
  7. #define PB push_back
  8. #define lson o<<1,l,mid
  9. #define rson o<<1|1,mid+1,r
  10. #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
  11. #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
  12. #define MEM(x,v) memset(x,v,sizeof(x))
  13. inline ll read(){
  14. char ch=getchar();ll x=0,f=0;
  15. while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
  16. while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  17. return f?-x:x;
  18. }
  19. int n,a,b,x[maxn],y[maxn],el,head[maxn],to[maxn],nxt[maxn],f[maxn][maxn][2],fpre[maxn][maxn][2],dp[maxn][maxn][2],mn[maxn][2];
  20. int fa[maxn],sz[maxn],son[maxn],dep[maxn],top[maxn];
  21. inline void add(int u,int v){
  22. to[++el]=v;nxt[el]=head[u];head[u]=el;
  23. }
  24. void dfs1(int u,int f){
  25. dep[u]=dep[fa[u]=f]+1;
  26. sz[u]=1;
  27. for(int i=head[u];i;i=nxt[i]){
  28. int v=to[i];
  29. dfs1(v,u);
  30. sz[u]+=sz[v];
  31. if(sz[v]>sz[son[u]]) son[u]=v;
  32. }
  33. }
  34. void dfs2(int u,int topf){
  35. top[u]=topf;
  36. if(son[u]) dfs2(son[u],topf);
  37. for(int i=head[u];i;i=nxt[i]){
  38. int v=to[i];
  39. if(v==son[u]) continue;
  40. dfs2(v,v);
  41. }
  42. }
  43. int lca(int u,int v){
  44. while(top[u]!=top[v]){
  45. if(dep[top[u]]<dep[top[v]]) swap(u,v);
  46. u=fa[top[u]];
  47. }
  48. return dep[u]<dep[v]?u:v;
  49. }
  50. int main(){
  51. n=read();
  52. a=read();
  53. FOR(i,2,a) add(read(),i);
  54. dep[0]=-1;
  55. dfs1(1,0);dfs2(1,1);
  56. FOR(i,1,n) x[i]=read();
  57. ROF(i,n,1){
  58. int s=0;
  59. FOR(j,i,n){
  60. if(i==j) s=f[i][j][0]=dep[x[j]];
  61. else s+=f[i][j][0]=dep[x[j]]-dep[lca(x[j],x[i])];
  62. fpre[i][j][0]=fpre[i][j-1][0]+(i==j?f[j][j][0]:f[j-1][j][0]);
  63. }
  64. }
  65. el=0;MEM(head,0);MEM(to,0);MEM(nxt,0);MEM(fa,0);MEM(sz,0);MEM(son,0);MEM(dep,0);MEM(top,0);
  66. b=read();
  67. FOR(i,2,b) add(read(),i);
  68. dep[0]=-1;
  69. dfs1(1,0);dfs2(1,1);
  70. FOR(i,1,n) y[i]=read();
  71. ROF(i,n,1){
  72. int s=0;
  73. FOR(j,i,n){
  74. if(i==j) s=f[i][j][1]=dep[y[j]];
  75. else s+=f[i][j][1]=dep[y[j]]-dep[lca(y[j],y[i])];
  76. fpre[i][j][1]=fpre[i][j-1][1]+(i==j?f[j][j][1]:f[j-1][j][1]);
  77. }
  78. }
  79. MEM(dp,0x3f);MEM(mn,0x3f);
  80. dp[0][0][0]=dp[0][0][1]=mn[1][0]=mn[1][1]=0;
  81. FOR(i,1,n) FOR(j,1,i){
  82. dp[i][j][0]=fpre[j][i][0]+mn[j][1];
  83. dp[i][j][1]=fpre[j][i][1]+mn[j][0];
  84. if(i!=n){
  85. mn[i+1][0]=min(mn[i+1][0],dp[i][j][0]+(j==1?0:f[j-1][i+1][1]-f[i+1][i+1][1]));
  86. mn[i+1][1]=min(mn[i+1][1],dp[i][j][1]+(j==1?0:f[j-1][i+1][0]-f[i+1][i+1][0]));
  87. }
  88. }
  89. int ans=1e9;
  90. FOR(j,1,n) ans=min(ans,min(dp[n][j][0],dp[n][j][1]));
  91. printf("%d\n",a+b-2-ans);
  92. }

CF1263F Economic Difficulties(DP)的更多相关文章

  1. LightOJ 1033 Generating Palindromes(dp)

    LightOJ 1033  Generating Palindromes(dp) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid= ...

  2. lightOJ 1047 Neighbor House (DP)

    lightOJ 1047   Neighbor House (DP) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87730# ...

  3. UVA11125 - Arrange Some Marbles(dp)

    UVA11125 - Arrange Some Marbles(dp) option=com_onlinejudge&Itemid=8&category=24&page=sho ...

  4. 【POJ 3071】 Football(DP)

    [POJ 3071] Football(DP) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4350   Accepted ...

  5. 初探动态规划(DP)

    学习qzz的命名,来写一篇关于动态规划(dp)的入门博客. 动态规划应该算是一个入门oier的坑,动态规划的抽象即神奇之处,让很多萌新 萌比. 写这篇博客的目标,就是想要用一些容易理解的方式,讲解入门 ...

  6. Tour(dp)

    Tour(dp) 给定平面上n(n<=1000)个点的坐标(按照x递增的顺序),各点x坐标不同,且均为正整数.请设计一条路线,从最左边的点出发,走到最右边的点后再返回,要求除了最左点和最右点之外 ...

  7. 2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)

    .navbar-nav > li.active > a { background-image: none; background-color: #058; } .navbar-invers ...

  8. Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)

    Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...

  9. 最长公共子序列长度(dp)

    /// 求两个字符串的最大公共子序列长度,最长公共子序列则并不要求连续,但要求前后顺序(dp) #include <bits/stdc++.h> using namespace std; ...

随机推荐

  1. C lang:Definition function

    Ax_note in parameter for show_n_char() is formal parameter Aa_Definition function #include <stdio ...

  2. simple go web application & 二维码生成 & 打包部署

    go语言简易web应用 & 二维码生成及解码 & 打包部署 转载请注明出处: https://www.cnblogs.com/funnyzpc/p/10801476.html 前言(闲 ...

  3. Oracle11G_R2中共享服务器模式和专用服务器模式参数解释及设置

    sys@MYTESTDB> show parameterNAME TYPE VALUE------------------------------------ ----------- ----- ...

  4. Mybatis XML映射文件

    mybatis为聚焦于SQL而构建,SQL映射文件常用的顶级元素如 resultMap,是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象. insert,映射插入语句 update, ...

  5. Nginx日志常见时间变量解析

    $request_time 官方解释:request processing time in seconds with a milliseconds resolution; time elapsed b ...

  6. C语言基本数据类型的转换

    变量的数据类型是可以转换的.转换的方法有两种,一种是自动转换,一种是强制转换.自动转换发生在不同数据类型的量混合运算时,由编译系统自动完成.自动转换遵循以下规则:1) 若参与运算量的类型不同,则先转换 ...

  7. dp习题

    仅收录有意思的题目 数的划分 导弹拦截 : LIS的两种优化 教主的花园:将不同的情况分类,最后取max 午餐 & 挂饰: 需要排序 挂饰:0-1背包处理负数体积 投资的最大效益 : 完全背包 ...

  8. vue 中的小知识点

    1)使用is解决小bug <!DOCTYPE html><html lang="en"> <head> <meta charset=&qu ...

  9. JSON对象转JAVA对象--com.alibaba.fastjson.JSONObject

    打印结果:

  10. 3万字长文概述:通俗易懂告诉你什么是.NET?什么是.NET Framework?什么是.NET Core?

    [转载]通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? 什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的 ...