E. Buds Re-hanging

对于这个题该开始还是没想法的,但这显然是个思维题,还是要多多动手推样例,实践一下。

简化题意:给定一个有根树,规定某个点为树干,当且仅当这个点不是根,且这个点至少有一个儿子,这个点的所有儿子都是叶子节点。每次可以将一个树干及其子树分离出来,然后将这个点与树上其他点相连。问:进行若干次操作之后,整个树的最少的叶子结点的个数?

首先我思考的是:我们这个树干从原来的父亲节点摘下来后要放到哪里,可以发现如果练到一个非叶子节点上的话,总的叶子数量是不会减少的,甚至有可能增多(因为原本树干的父亲可能成为新的叶子)。所以最优的情况一定是将这个树干连到一个叶子节点上。可以发现对于任意一个树的结构我们都可以从叶子节点往上,依次将他们拆离,也就是每次都将当前所有的树干摘离,那么最后只有两种结果,根节点不能被拆离,只剩下根节点一个点,根节点也能被摘离,整棵树都能被拆离。那么对于当前一个点x而言,我们要如何操作,才能使得整个的叶子节点最少。对于x的所有儿子y,我们期望的最优结果就是所有儿子都能够摘离除去,放到其中一个儿子身上,类似一个链的形状。这样的话,叶子节点最少。考虑这样我们需要儿子的那些信息,如何统计答案?首先需要儿子能不能被完全摘离,还有儿子内部经过调整之后的最少的叶子节点。起初令\(ans[x]=\sum ans[y]\),之后,若有一个儿子能够完全被摘离,那\(ans[x]--\),因为我们可以将y这个儿子及其子树全部摘离,放到另一个子树上,减少一个叶子结点。但有一种情况比较特殊,就是当全部的儿子都能被摘离时,我们要将\(ans[x]++\),因为我们至少留一个儿子放上面。那么考虑x是否能被摘离,若x的全部儿子都能被摘离,则x不能被摘离,否则x就能被摘离。直接树形DP即可。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=2e5+10;
  4. int n,f[N];
  5. vector<int>son[N];
  6. inline bool dfs(int x,int fa)//bool表示能不能被摘离.
  7. {
  8. int children=0,cnt=0;//cnt表示能被摘离的儿子的个数。
  9. for(auto y:son[x])
  10. {
  11. if(y==fa) continue;
  12. children++;
  13. if(dfs(y,x)) cnt++;
  14. f[x]+=f[y];
  15. }
  16. f[x]-=cnt;
  17. if(cnt==children) f[x]++;
  18. if(children==0) {f[x]=1;return 0;}
  19. return (cnt==children)?0:1;
  20. }
  21. int main()
  22. {
  23. // freopen("1.in","r",stdin);
  24. int T;cin>>T;
  25. while(T--)
  26. {
  27. cin>>n;
  28. for(int i=1;i<=n;++i) son[i].clear();
  29. for(int i=1;i<n;++i)
  30. {
  31. int x,y;cin>>x>>y;
  32. son[x].push_back(y);
  33. son[y].push_back(x);
  34. }
  35. memset(f,0,sizeof(f));
  36. dfs(1,0);
  37. cout<<f[1]<<endl;
  38. }
  39. return 0;
  40. }

F. Points Movement

简化题意:给定你一些点和区间,点可以左右移动,当一个点处于某个线段中时成这个区间被访问过,问最少移动的次数使得所有的区间被访问过?

首先可以发现一些小的结论,若某个区间完全包含另一个区间的话,则那个大的区间就不必考虑了,因为若访问过小的区间,则大的区间也一定被访问了。其次,对于初始位置而言,若某个点在某个区间内的话,则这个区间也不用被考虑。这样的话,我们将不必考虑的区间都剔除,考虑剩下的区间和点构成什么了?我们将区间按左端点排序,可以发现右端点一定也是有序的,若出现有序,则一定会出现大包小的情况,在第一步就被我们剔除掉了。剩下的点和区间一定是相间分布的,即点,区间,点,区间...这样分布的,其次我们考虑某个区间被访问时一定只是其端点被访问,且访问的点一定是向左,向右离他最近的点,也就是说点的移动不会跨过另一个点,否则我们移动另一个点一定更优。

考虑以下这个区间我们有多少种情况:



首先这三个区间我们一定是用A和B移动去访问他们,那这里就有以下方案:

1.A去\(L_3\)

2.A去\(L_2\),B去\(R_3\)

3.A去\(L_1\),B去\(R_2\)

4.B去\(R_1\)

发现这里的方案数为O(K)k是区间的数量。但考虑到如果某两个区间的中间夹的点数只有一个。那么这个点可能先往左边跑,之后再往右边跑,这个怎么解决,所以我们需要知道点的位置。由于每个点左右跑的话一定会回到原位置,所以我们可以分开统计答案,每个点可以到某个区间端点不动了,也可以到区间端点再返回原位置,所以我们记录f[i][0/1]表示第i个点之前所有的区间都访问过,且这个点不返回位,返回原位,的最少的移动步数。注意这里点左右跑的话可能有两个选择,可以先向左边跑,再向右边跑,也可以先向右边跑,再向做边跑。注意转移状态的时候别漏就行。

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int N=2e5+10;
  5. int n,m;
  6. ll f[N][2],a[N],L[N],R[N];
  7. struct segment{int l,r;};
  8. vector<segment>v;
  9. inline bool cmp(segment x,segment y)
  10. {
  11. return (x.l!=y.l)?(x.l<y.l):(x.r>y.r);
  12. }
  13. int main()
  14. {
  15. //freopen("1.in","r",stdin);
  16. int T;cin>>T;
  17. while(T--)
  18. {
  19. scanf("%d%d",&n,&m);
  20. for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
  21. sort(a+1,a+n+1);v.clear();
  22. for(int i=1;i<=m;++i)
  23. {
  24. int l,r;scanf("%d%d",&l,&r);
  25. int id=lower_bound(a+1,a+n+1,l)-a;
  26. if(id==n+1||a[id]>r)
  27. {
  28. v.push_back((segment){l,r});
  29. }
  30. }
  31. sort(v.begin(),v.end(),cmp);
  32. for(int i=0;i<v.size();++i)
  33. {
  34. if(i!=0&&v[i].r<=v[i-1].r)
  35. {
  36. v.erase(v.begin()+i-1);
  37. i-=2;
  38. }
  39. }
  40. for(int i=1;i<=n+1;++i) f[i][0]=f[i][1]=1e18;
  41. f[0][0]=f[0][1]=0;
  42. a[0]=-1e18;a[n+1]=1e18;
  43. int now=0;//now表示当前处理到的区间。
  44. for(int i=1;i<=n+1;++i)
  45. {
  46. int cnl=0,cnr=0;//L表示左边点到达的终点,R表示右边点到达的终点。
  47. L[++cnl]=a[i-1];
  48. while(now<v.size()&&v[now].r<a[i])
  49. {
  50. L[++cnl]=v[now].l;
  51. R[++cnr]=v[now].r;
  52. ++now;
  53. }
  54. R[++cnr]=a[i];
  55. for(int j=1;j<=cnl;++j)
  56. {
  57. f[i][0]=min(f[i][0],f[i-1][1]+L[j]-a[i-1]+a[i]-R[j]);
  58. f[i][1]=min(f[i][1],f[i-1][1]+L[j]-a[i-1]+(a[i]-R[j])*2);
  59. f[i][0]=min(f[i][0],f[i-1][0]+(L[j]-a[i-1])*2+a[i]-R[j]);
  60. f[i][1]=min(f[i][1],f[i-1][0]+(L[j]-a[i-1])*2+(a[i]-R[j])*2);
  61. }
  62. }
  63. printf("%lld\n",min(f[n+1][1],f[n+1][0]));
  64. }
  65. return 0;
  66. }

Codeforces Global Round 16题解的更多相关文章

  1. Codeforces Global Round 2 题解

    Codeforces Global Round 2 题目链接:https://codeforces.com/contest/1119 A. Ilya and a Colorful Walk 题意: 给 ...

  2. Codeforces Global Round 3 题解

    这场比赛让我上橙了. 前三题都是大水题,不说了. 第四题有点难想,即使想到了也不能保证是对的.(所以说下面D的做法可能是错的) E的难度是 $2300$,但是感觉很简单啊???说好的歪果仁擅长构造的呢 ...

  3. Codeforces Global Round 4 题解

    技不如人,肝败吓疯…… 开场差点被 A 题意杀了,幸好仔细再仔细看,终于在第 7 分钟过掉了. 跟榜.wtf 怎么一群人跳题/倒序开题? 立刻紧张,把 BC 迅速切掉,翻到了 100+. 开 D.感觉 ...

  4. Codeforces Global Round 1 (A-E题解)

    Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...

  5. Codeforces Global Round 11 个人题解(B题)

    Codeforces Global Round 11 1427A. Avoiding Zero 题目链接:click here 待补 1427B. Chess Cheater 题目链接:click h ...

  6. CodeForces Global Round 1

    CodeForces Global Round 1 CF新的比赛呢(虽然没啥区别)!这种报名的人多的比赛涨分是真的快.... 所以就写下题解吧. A. Parity 太简单了,随便模拟一下就完了. B ...

  7. Codeforces Global Round 1 - D. Jongmah(动态规划)

    Problem   Codeforces Global Round 1 - D. Jongmah Time Limit: 3000 mSec Problem Description Input Out ...

  8. Codeforces Global Round1 简要题解

    Codeforces Global Round 1 A 模拟即可 # include <bits/stdc++.h> using namespace std; typedef long l ...

  9. Codeforces Beta Round #16 E. Fish (状压dp)(概率dp)

    Codeforces Beta Round #16 (Div. 2 Only) E. Fish 题目链接:## 点击打开链接 题意: 有 \(n\) 条鱼,每两条鱼相遇都会有其中一只吃掉对方,现在给你 ...

随机推荐

  1. java.net.NoRouteToHostException: Cannot assign requested address

    今天压力测试时, 刚开始出现了很多异常, 都是 java.net.NoRouteToHostException: Cannot assign requested address.  经网上查资料, 是 ...

  2. 【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token

    问题描述 在APIM中配置对传入的Token进行预验证,确保传入后端被保护的API的Authorization信息正确有效,可以使用validate-jwt策略.validate-jwt 策略强制要求 ...

  3. linux重启mysql

    一. 启动1.使用 service 启动:service mysql start2.使用 mysqld 脚本启动:/etc/inint.d/mysql start3.使用 safe_mysqld 启动 ...

  4. python学习笔记(七)-函数

    函数 方法 功能说白了,函数就是把一堆代码组合到一起,变成一个整体.函数不调用不会被执行.作用在于提高代码的复用性.定义函数 def greet_user(): """关 ...

  5. 关于open falcon 与nightingale 的一些调研

    针对 open-falcon 与 nightingale 的调研 一.open-falcon 1.1 组件介绍 1.1.1 agent > agent用于采集机器负载监控指标,比如cpu.idl ...

  6. Python3入门系列之-----字符串

    字符串 字符串是由数字,字母.下划线组成的一串字符 创建字符串,可以使用单引号和双引号: var1 = 'Hello World!'var2 = "Hello World!" 学习 ...

  7. WPF进阶技巧和实战03-控件(5-列表、树、网格02)

    数据模板 样式提供了基本的格式化能力,但是不管如何修改ListBoxItem,他都不能够展示功能更强大的元素组合,因为了每个ListBoxItem只支持单个绑定字段(通过DisplayMemberPa ...

  8. mybatis本地缓存&分布式缓存干货分享

    前言:干货记录学习mybatis实际开发中缓存的使用. 环境: springboot2.X + mybatis3.x Mybatis是一款持久层框架,它提供了一级缓存和二级缓存. 名词解释 一级缓存( ...

  9. Java实现爬取京东手机数据

    Java实现爬取京东手机数据 最近看了某马的Java爬虫视频,看完后自己上手操作了下,基本达到了爬数据的要求,HTML页面源码也刚好复习了下,之前发布两篇关于简单爬虫的文章,也刚好用得上.项目没什么太 ...

  10. 超详细的Eureka源码解析

    Eureka简介 Eureka是什么? Eureka是基于REST(Representational State Transfer)服务,主要以AWS云服务为支撑,提供服务发现并实现负载均衡和故障转移 ...