CF习题集二

一、CF507E Breaking Good

题目描述

\(Breaking Good\)这个游戏对于有经验的玩家来说也有一定的难度。

游戏的主角小明希望加入一个叫斧头帮的犯罪团伙。这个团伙控制着整个国家\(n\)个城市间的\(m\)条双向道路,这些道路保证没有自环和重边,任何城市可以通过这些道路到达任何其他城市。

然而道路并不全都能通行,有些道路是需要修复。

现在这个团伙要搞一个大新闻!搞事地点位于城市\(1\)。像往常一样,这个行动最难的部分是搞事后如何逃到他们在城市n的总部。为了获得该团伙的信任,小明决定负责这项搞事行动,而且他提出了一个看起来很明智的计划。

首先,他们将在从城市1返回途中使用的路径总长度必须尽可能短;然后,为了让搞的大新闻更加刺激,他们必须炸毁所有不在这条路径上的其他道路。但是他们不必炸掉不能通行的道路。

如果选择的道路有一些不能通行的道路,他们将不得不在行动之前修复那些道路。

小明发现,有很多路径满足了条件\(1\)(即尽可能短),所以他决定在其中选择一条路径,使受影响道路的总数最小化。

你能帮助小明完成搞事并获得该团伙的信任吗?

分析

首先,我们要选择一条最短的路径

在路径最短的基础上,我们要尽量使受影响的道路数更少

因此我们要在跑\(Dij\)的结构体里存储三个东西

即当前节点的编号,当前节点距离起点的最短路径,当前路径下更改的道路条数

在进行松弛操作时,如果\(dis[u]>dis[now]+b[i].val\)

那么我们像之前那样更新\(dis\)值即可

如果\(dis[u]=dis[now]+b[i].val\)但是新的路径更改的道路条数更少

此时我们也需要更新

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=1e6+5;
  4. int head[maxn],tot=1;
  5. struct asd{
  6. int from,to,next,val,jud;
  7. }b[maxn];
  8. void ad(int aa,int bb,int cc,int dd){
  9. b[tot].from=aa;
  10. b[tot].to=bb;
  11. b[tot].next=head[aa];
  12. b[tot].val=cc;
  13. b[tot].jud=dd;
  14. head[aa]=tot++;
  15. }
  16. struct jie{
  17. int num,jl,hf;
  18. jie(int aa,int bb,int cc){
  19. num=aa,jl=bb,hf=cc;
  20. }
  21. bool operator < (const jie& A) const{
  22. if(jl==A.jl) return hf>A.hf;
  23. return jl>A.jl;
  24. }
  25. };
  26. priority_queue<jie> q;
  27. bool viss[maxn];
  28. int dis[maxn],jl[maxn],hf[maxn];
  29. void dij(){
  30. memset(dis,0x3f,sizeof(dis));
  31. memset(hf,0x3f,sizeof(hf));
  32. dis[1]=0;
  33. hf[1]=0;
  34. q.push(jie(1,0,0));
  35. while(!q.empty()){
  36. int now=q.top().num;
  37. int nhf=q.top().hf;
  38. q.pop();
  39. if(viss[now]) continue;
  40. viss[now]=1;
  41. for(int i=head[now];i!=-1;i=b[i].next){
  42. int u=b[i].to;
  43. if(dis[u]>dis[now]+b[i].val){
  44. dis[u]=dis[now]+b[i].val;
  45. jl[u]=i;
  46. hf[u]=nhf+b[i].jud;
  47. q.push(jie(u,dis[u],hf[u]));
  48. } else if(dis[u]==dis[now]+b[i].val){
  49. if(hf[u]>nhf+b[i].jud){
  50. jl[u]=i;
  51. hf[u]=nhf+b[i].jud;
  52. q.push(jie(u,dis[u],hf[u]));
  53. }
  54. }
  55. }
  56. }
  57. }
  58. vector<int> g;
  59. bool vis[maxn];
  60. int main(){
  61. memset(head,-1,sizeof(head));
  62. int n,m;
  63. scanf("%d%d",&n,&m);
  64. for(int i=1;i<=m;i++){
  65. int aa,bb,cc;
  66. scanf("%d%d%d",&aa,&bb,&cc);
  67. ad(aa,bb,1,cc^1);
  68. ad(bb,aa,1,cc^1);
  69. }
  70. dij();
  71. int ans=0;
  72. int now=n;
  73. while(jl[now]){
  74. if(jl[now]%2==0) g.push_back(jl[now]-1);
  75. else g.push_back(jl[now]);
  76. now=b[jl[now]].from;
  77. }
  78. for(int i=0;i<g.size();i++){
  79. vis[g[i]]=1;
  80. }
  81. for(int i=1;i<tot;i+=2){
  82. if(vis[i]){
  83. if(b[i].jud==1){
  84. ans++;
  85. }
  86. } else {
  87. if(b[i].jud==0){
  88. ans++;
  89. }
  90. }
  91. }
  92. printf("%d\n",ans);
  93. for(int i=1;i<tot;i+=2){
  94. if(vis[i]){
  95. if(b[i].jud==1){
  96. printf("%d %d %d\n",b[i].from,b[i].to,1);
  97. }
  98. } else {
  99. if(b[i].jud==0){
  100. ans++;
  101. printf("%d %d %d\n",b[i].from,b[i].to,0);
  102. }
  103. }
  104. }
  105. return 0;
  106. }

二、CF467C George and Job

题目描述

新款手机 \(iTone6\) 近期上市,\(George\) 很想买一只。不幸地,\(George\) 没有足够的钱,所以 \(George\) 打算当一名程序猿去打工。现在\(George\)遇到了一个问题。 给出一组有 \(n\) 个整数的数列\(p_1,p_2,...,p_n\),你需要挑出 \(k\) 组长度为 \(m\) 的数,要求这些数互不重叠 即$ [l_{1},r_{1}],[l_{2},r_{2}],...,[l_{k},r_{k}] (1<=l_{1}<=r_{1}<l_{2}<=r_{2}<...<l_{k}<=r_{k}<=n;r_{i}-l_{i}+1=m)[l1​,r1​],[l2​,r2​],...,[lk​,rk​]$

使选出的数的和值最大,请你帮助George码出这份代码

分析

我们设\(f[i][j]\)为前\(i\)个数选出了\(j\)组,其中第\(i\)个数必须选的最大值

那么我们就可以写出如下的状态转移方程

  1. f[i][k]=max(f[i][k],f[j][k-1]+sum[i]-sum[i-m]);

时间复杂度为\(O(n^3)\)

实际上,我们可以用单调队列对于每一个\(i\)维护\(f[j][k-1]\)的最大值

这样时间复杂度就降到了\(O(n^2)\)

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=5e3+5;
  4. #define int long long
  5. int sum[maxn],a[maxn],f[maxn][maxn],q[maxn],head,tail;
  6. signed main(){
  7. int n,m,p;
  8. scanf("%lld%lld%lld",&n,&m,&p);
  9. for(int i=1;i<=n;i++){
  10. scanf("%lld",&a[i]);
  11. sum[i]=sum[i-1]+a[i];
  12. }
  13. int ans=0;
  14. for(int j=1;j<=p;j++){
  15. head=1,tail=1;
  16. memset(q,0,sizeof(q));
  17. for(int i=m;i<=n;i++){
  18. if(head<=tail)f[i][j]=max(f[i][j],f[q[head]][j-1]+sum[i]-sum[i-m]);
  19. while(head<=tail && f[i-m+1][j-1]>f[q[tail]][j-1]) tail--;
  20. q[++tail]=i-m+1;
  21. ans=max(ans,f[i][p]);
  22. }
  23. }
  24. printf("%lld\n",ans);
  25. return 0;
  26. }

三、CF333E Summer Earnings

题目描述

在一个平面内给出\(n\)个点的坐标,任选其中三个为圆心作半径相同的圆,要求这三个圆不能相交但可以相切,求能画出的圆中的最大半径。

分析

对于平面上的三个点,我们可以将其分为两种情况

一种情况是三个点都位于一条直线上

此时我们的最大直径只能是三点当中距离最小的两点的距离

还有一种情况是三个点不在同一条直线上

此时我们的最大直径也只能是三点当中距离最小的两点的距离

因为我们要保证圆只能相切,不能相交

如果直径再大一点,势必会出现相交的情况

所以我们可以先预处理出任意两点间的距离,然后按距离从小到大排好序

每次取出两个点,我们就判断一下它们是否和同一个点已经连到一起

如果已经连到一起,我们就输出当前答案,否则继续寻找

而判断两个点是否和同一个点连到一个我们可以用\(bitset\)解决

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef double dd;
  4. const int maxn=3005;
  5. dd jlx[maxn],jly[maxn];
  6. bitset<maxn> g[maxn];
  7. struct asd{
  8. int from,to;
  9. dd da;
  10. }b[maxn*maxn];
  11. dd solve(int aa,int bb){
  12. return (dd)sqrt((jlx[aa]-jlx[bb])*(jlx[aa]-jlx[bb])+(jly[aa]-jly[bb])*(jly[aa]-jly[bb]));
  13. }
  14. bool cmp(asd aa,asd bb){
  15. return aa.da>bb.da;
  16. }
  17. int main(){
  18. int n,cnt=0;
  19. scanf("%d",&n);
  20. for(int i=1;i<=n;i++){
  21. scanf("%lf%lf",&jlx[i],&jly[i]);
  22. }
  23. for(int i=1;i<=n;i++){
  24. for(int j=i+1;j<=n;j++){
  25. if(i==j) continue;
  26. b[++cnt].da=solve(i,j);
  27. b[cnt].from=i;
  28. b[cnt].to=j;
  29. }
  30. }
  31. sort(b+1,b+1+cnt,cmp);
  32. for(int i=1;i<=cnt;i++){
  33. int aa=b[i].from,bb=b[i].to;
  34. g[aa][bb]=1,g[bb][aa]=1;
  35. if((g[aa] & g[bb]).count()){
  36. printf("%.20lf\n",b[i].da/2.0);
  37. exit(0);
  38. }
  39. }
  40. return 0;
  41. }

四、CF132C Logo Turtle

题目描述

很多人把\(LOGO\)编程语言和海龟图形联系起来。在这种情况下,海龟沿着直线移动,接受命令“T”(“转向180度”)和“F”(“向前移动1单元”)。

你会收到一份给海龟的命令清单。你必须从列表中精确地改变N个命令(一个命令可以被改变多次)。要求出海龟在遵循修改后的所有命令后,会从起点最远可以移到多远?

分析

传送门

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=105;
  4. char s[maxn];
  5. int f[maxn][maxn][3],wz[maxn];
  6. int main(){
  7. for(int i=0;i<maxn;i++){
  8. for(int j=0;j<maxn;j++){
  9. f[i][j][1]=f[i][j][0]=-0x3f3f3f3f;
  10. }
  11. }
  12. scanf("%s",s+1);
  13. int n;
  14. scanf("%d",&n);
  15. int len=strlen(s+1);
  16. f[0][0][0]=0;
  17. f[0][0][1]=0;
  18. for(int i=1;i<=len;i++){
  19. for(int j=0;j<=n;j++){
  20. for(int k=0;k<=j;k++){
  21. if(s[i]=='F'){
  22. if(k&1){
  23. f[i][j][0]=max(f[i][j][0],f[i-1][j-k][1]);
  24. f[i][j][1]=max(f[i][j][1],f[i-1][j-k][0]);
  25. } else {
  26. f[i][j][0]=max(f[i][j][0],f[i-1][j-k][0]+1);
  27. f[i][j][1]=max(f[i][j][1],f[i-1][j-k][1]-1);
  28. }
  29. } else {
  30. if(k&1){
  31. f[i][j][0]=max(f[i][j][0],f[i-1][j-k][0]+1);
  32. f[i][j][1]=max(f[i][j][1],f[i-1][j-k][1]-1);
  33. } else {
  34. f[i][j][0]=max(f[i][j][0],f[i-1][j-k][1]);
  35. f[i][j][1]=max(f[i][j][1],f[i-1][j-k][0]);
  36. }
  37. }
  38. }
  39. }
  40. }
  41. printf("%d\n",max(f[len][n][0],f[len][n][1]));
  42. return 0;
  43. }

CF习题集二的更多相关文章

  1. CF习题集一

    CF习题集一 一.CF915E Physical Education Lessons 题目描述 \(Alex\)高中毕业了,他现在是大学新生.虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意 ...

  2. CF习题集三

    CF习题集三 一.CF8C Looking for Order 题目描述 \(Lena\)喜欢秩序井然的生活.一天,她要去上大学了.突然,她发现整个房间乱糟糟的--她的手提包里的物品都散落在了地上.她 ...

  3. 《Java练习题》习题集二

    编程合集: https://www.cnblogs.com/jssj/p/12002760.html Java总结:https://www.cnblogs.com/jssj/p/11146205.ht ...

  4. Unity3D编程学习分享

    学习地址:http://www.ixueyun.com/lessons/detail-lessonId-692.html 一.课程概述: 以前大部分3D游戏出现在pc和ps.XBox等专业游戏主机上, ...

  5. 【一天一道LeetCode】#17. Letter Combinations of a Phone Number

    一天一道LeetCode (一)题目 Given a digit string, return all possible letter combinations that the number cou ...

  6. Javassist 字节码 简介 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  7. Zookeeper 系列(五)Curator API

    Zookeeper 系列(五)Curator API 一.Curator 使用 Curator 框架中使用链式编程风格,易读性更强,使用工程方法创建连接对象使用. (1) CuratorFramewo ...

  8. shell工具使用配置备忘

    一.bash之vi mode.两种方式:set -o vi(只让bash自己进入vi模式)或 set editing-mode vi(让所有使用readline库函数的程序在读取命令行时都进入vi模式 ...

  9. 《Java练习题》Java编程题合集(全)

    前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题. 初学者: <Java练习题>习题集一   https://www.cnblogs.com/jssj/ ...

随机推荐

  1. C++中复杂声明和定义的辨析

    0x00 前言 c++中的复杂声明往往令人无法下手,经常使人搞错这到底声明的是一个指针还是指针函数.但其实c++对于复杂声明是遵循一定的规则的,叫做变量名—>右--左-右规则. 0x01 规则解 ...

  2. 安装FeedReader添加RSS订阅

    #0x1 FeedReader FeedReader是一款功能齐全,界面优美的GTK+ 3RSS阅读器客户端,用于在线RSS服务. FeedReader目前支持Feedbin,Feedly,Fresh ...

  3. 一、python 基础之基础语法

    一.变量命名规则 1.驼峰命名 大驼峰 MyName = 'leon' 小驼峰 myName = 'Amy' 2.下划线命名 my_name = 'jack' 建议:变量名或者文件名使用下划线命名方式 ...

  4. Scala 面向对象(十二):嵌套类

    在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构.如在类中可以再定义一个类,这样的类是嵌套类,其他语法结构也是一样. 嵌套类类似于Java中的内部类. Scala嵌套类的使用1 请编写程序, ...

  5. Maven [ERROR] 不再支持源选项 5,请使用 7 或更高版本的解决办法

    刚刚学Maven,当我点击test时 就出现了这两个错误: [ERROR] 不再支持源选项 5.请使用 7 或更高版本.[ERROR] 不再支持目标选项 5.请使用 7 或更高版本. 后来在看到这篇文 ...

  6. Linux07 /redis的配置、五大数据类型、发布订阅、持久化、主从复制、哨兵配置、集群搭建

    Linux07 /redis的配置.五大数据类型.发布订阅.持久化.主从复制.哨兵配置.集群搭建 目录 Linux07 /redis的配置.五大数据类型.发布订阅.持久化.主从复制.哨兵配置.集群搭建 ...

  7. 数据可视化之分析篇(八)Power BI数据分析应用:结构百分比分析法

    https://zhuanlan.zhihu.com/p/113113765 PowerBI数据分析02:结构百分比分析法 作者:海艳 结构百分比分析法,又称纵向分析,是指同一期间财务报表中不同项目间 ...

  8. js 中 attachEvent 简示例

    attachEvent绑定事件,函数的默认this指向为window,要解决问题可以通过call改变方法的指向! var div = document.getElementsByTagName('di ...

  9. 太实用了!自己动手写软件——GUI编程

    这几天我有一个想法就是将我之前做测试写的一些协议脚本(如:ssh.FTP.SMTP.MySQL.Oracle等)综合在一起做一个密码PJ器,这么多的协议放在一起,每个协议都有自己特殊的参数,如果还是和 ...

  10. 【译】GraalVM—下一代JVM介绍

    原标题:GraalVM – an introduction to the next level JVM 随着Red Hat宣布Quarkus作为- 为GraalVM和HotSpot量身定制的下一代Ku ...