推荐生要凉辽

这可能是我更新的最后一篇博客

代码什么的有时间再说吧,先讲思路。(已搞定前三题代码)

首先先看一下线段覆盖题。我们有一个区间,要用线段覆盖整个区间。

这个是线段的覆盖简图。我们如何选取最少的线段来覆盖整个区间呢?先将右端点排序,再将左端点贪心一下。

比如:

但在这个题里面覆盖的是格子,不一定连续。这就比较复杂了,我们要想点办法。我们线段覆盖解决的是格子连续的情况。所以我们要先证明第一行每个格子里的蓄水池覆盖第n行的格子是连续的。

如果从i无法流到j,而能流到j-1和j+1,从别的城市可以流到j,那么这两条路线一定有一个交点,那么i也可以从这个交点流到j,这与条件矛盾。

然后这就是一个线段覆盖的问题了。因为在第1行的城市对第n行的城市覆盖的区间是连续的,就相当于在第n行进行线段盖。

我们解决能否到达时,就用dfs/bfs求一遍,顺便把第一行每个城市覆盖的第n行城市求出来,然后进行线段覆盖。

这样会T一个点,所以我们要有个优化:第一行只有比两边都搞的点才进行搜索,如果有一边比这个点高,那这个点所覆盖的区域肯定在比这个点高的子集里面。

以及注意一下n=1的情况,下面代码里会讲

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<queue>
  7. using namespace std;
  8. int n,m,a[][],k,ans,ans2;
  9. int dx[]={,-,,},dy[]={,,,-};
  10. struct xianduan
    {//处理线段
  11. int l, r;
  12. xianduan()//构造函数(结构体初始化)
  13. {l=2147483647;
  14. r=-;
  15. }
  16. }xd[];//记录第一行每个点覆盖的第n行的区间
  17. bool vis[][],vis2[];//vis记录在一次搜索中走过的点,vis2记录最后一行被覆盖的点
  18. bool check()
  19. {bool c=;
  20. for(int i=;i<=m;i++)//判断最后一行是否都被覆盖
  21. {
  22. if(!vis2[i]){c=;ans2++;}//如果有没被覆盖的,就统计个数
  23. }
  24. return c;
  25. }
  26. struct dl{
  27. int x,y;
  28. dl(int xx,int yy):x(xx),y(yy){}//构造函数*2
  29. };
  30. bool hf(int x,int y,int xx,int yy)//广搜时判断能不能走
  31. {
  32. if(xx<||yy<||xx>n||yy>m)return ;
  33. if(a[xx][yy]>=a[x][y])return ;
  34. if(vis[xx][yy])return ;
  35. return ;
  36. }
  37. queue <dl> q;
  38. void bfs(int st)//广搜模板
  39. { if(a[][st]<a[][st-]||a[][st]<a[][st+])return ;
  40. memset(vis,,sizeof(vis));//每次搜索记得清空,不然可能会出现什么意外
  41. vis[][st]=;
  42. while(!q.empty())
  43. {dl ex=q.front();
  44. q.pop();
  45. for(int i=;i<;i++)
  46. {int xx=ex.x,yy=ex.y;
  47. xx+=dx[i];yy+=dy[i];
  48. if(hf(ex.x,ex.y,xx,yy))
  49. {vis[xx][yy]=;
  50. q.push(dl(xx,yy));
  51. if(xx==n)
  52. {if(yy>xd[st].r){xd[st].r=yy;}//记录xd[i]
  53. if(yy<xd[st].l){xd[st].l=yy;}
  54. vis2[yy]=;//因为vis每次都要清空,所以才用vis2来记录
  55. }
  56. }
  57. }
  58. }
  59. }
  60. int main()
  61. {
  62. scanf("%d%d",&n,&m);
  63. for(int i=;i<=n;i++)
  64. for(int j=;j<=m;j++)
  65. scanf("%d",&a[i][j]);
  66. for(int i=;i<=m;i++)
  67. bfs(i);
  68. if(check())
  69. {int left=,r_max=;
  70. while(left<=m)
  71. {
  72. for(int i=;i<=m;i++)
  73. {if(xd[i].l<=left)r_max=max(r_max,xd[i].r);
  74. }
  75. ans++;
  76. left=r_max+;
  77. }
  78. printf("1\n%d\n",ans);
  79. }
  80. else
  81. { if(n==)printf("1\n%d\n",ans2);//n=1时的特判。因为当n=1时,每次出队的点的vis2并不会被标记,所以没有标记的点(1,j)就是建蓄水池的点
  82. else printf("0\n%d\n",ans2);
  83. }
  84. }

不枉我肝了近90行,wa了3次

我们先枚举第二个客栈j,找到j前面的第一个(从右往左)价格合理,颜色符合要求的客栈i。那么在i前面,颜色和i一样的客栈的数量+1就是当前j的方案数,如果在i后面,j前面还有颜色相同的客栈,那么这些客栈的方案数与j相同。

上面的式子在说些什么呢?就是当前以i为右端点的方案数,如果当前i客栈这种颜色出现的最大的地方(不包括i)k要比当前价钱合理的最大的地方t位置靠后的话,就是k的方案数。

当出现这种情况时:

更多细节请见代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<queue>
  7. const int MAXN=;
  8. using namespace std;
  9. int p,k,n,pre[MAXN],pos[],tot[],res[MAXN];
  10. struct kezhan{
  11. int col,mon;//col是coler,mon是money
  12. }a[MAXN];
  13. int main()
  14. {
  15. scanf("%d%d%d",&n,&k,&p);
  16. for(int i=;i<=n;i++)
  17. {scanf("%d%d",&a[i].col,&a[i].mon);
  18. if(a[i].mon<=p)pre[i]=i;//因为这里每个下标i对应的都是不一样的数,所以可以在输入中预处理
  19. else pre[i]=pre[i-];
  20. }
  21. for(int i=;i<=n;i++)
  22. {
  23. if(pre[i]<pos[a[i].col])//先dp,再统计tot和pos
  24. res[i]=res[pos[a[i].col]];
  25. if(pre[i]>=pos[a[i].col])
  26. res[i]=tot[a[i].col];
  27. pos[a[i].col]=i;
  28. tot[a[i].col]++;
  29. }
  30. long long ans=;
  31. for(int i=;i<=n;i++)//最后答案是每个i作为右端点的方案数的和
  32. ans+=res[i];
  33. printf("%lld",ans);
  34. }

交了6次才A,嘤嘤嘤

首先考虑并没有加速器的情况。

设wait[i]表示到i最晚的游客到达的时刻,设arrive[i]表示车到i点的时刻。

则arrive[i]=max(arive[i-1],wait[i-1])+d[i](d[i]就是路程)

现在我们加上加速器。

加速器可以减少距离,但并不能减少游客的到达时间,所以当游客的到达时刻大于汽车的到达时刻的时候,使用加速器就没有意义了。我们要让加速器有效,就选取arrive[i]比wait[i]大的点,进行加速,然后重复上面的过程,一直到加速器用完或是没有满足条件的边为止。

因为代码的维护不会写(树状数组优化复杂度神马的)然后翻洛谷题解,有了些新的收获。

1.这个题的维护不需要优化,因为o(n^2)也能过

2.这里贪心的是造福最多人民群众的区间(可能上课没好好听漏了点思路qwq我错惹)

代码什么的可能1个月之后才会出吧。

先理一理思路。

首先,我们预处理出车在每个点的等待时间。

递推计算每个点的arrive,并且统计在哪里会产生arrive大于wait并且用了加速器后能造福最多的人民群众,将这一段区间进行维护,一直到加速器用完为止。

维护的话,因为对一个[i,i+1]使用加速器后,可能影响到后面的arrive。如果后面的arrive>wait,就说明这里使用加速器会影响后面,否则不会。就跳出循环。

我们看到题,就会发现di的定义别扭的一批,所以我们改一下,有助于后面我们乱搞。

我们把di的定义改为从i-1到i的距离,读入就改为:

  1. for(int i=;i<=n;i++)
  2. scanf("%d",&d[i]);

注意是从i=2开始读入。

我们要选择造福人数最多的点,所以我们边读入边处理到达每个点的人数。在使用加速器的时候,每次都从头开始更新造福人最多的点(注意memset(不写memset爆0警告)),选出最多的点进行更新。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. using namespace std;
  7. int goal[],d[],m,k,n,wait[],arr[],yx[],max_i,max_yx;//yx[i]是选择在i-1到i的距离-1,造福的人数,arr[i]为到达第i个点的时刻,wait[i]是每个点要等多久
  8. struct c{
  9. int time,st,aim;
  10. }ck[];
  11. int main()
  12. {
  13. scanf("%d%d%d",&n,&m,&k);
  14. for(int i=;i<=n;i++)//注意i从2开始
  15. scanf("%d",&d[i]);
  16. for(int i=;i<=m;i++)
  17. {scanf("%d%d%d",&ck[i].time,&ck[i].st,&ck[i].aim);
  18. wait[ck[i].st]=max(wait[ck[i].st],ck[i].time);//处理每个点的等待时间
  19. goal[ck[i].aim]++;//统计每个点到达的人数
  20. }
  21. for(int i=;i<=n;i++)
  22. {arr[i]=max(arr[i-],wait[i-])+d[i];
  23. }
  24. while(k)//开始使用加速器
  25. { max_yx=;max_i=;
  26. memset(yx,,sizeof(yx));//一定一定要写
  27. for(int i=n;i>=;i--)//倒着写递推求yx,可以减少一重循环
  28. {
  29. if(d[i]==){yx[i]=;}//如果有d被减到了0,就肯定不能再减了,所以也就不会造福人了
  30. else
  31. {if(arr[i]>wait[i])
  32. {yx[i]+=goal[i];
  33. yx[i]+=yx[i+];//这样的i可以影响到i+1
  34. if(yx[i+]==&&wait[i+]==)
  35. yx[i]+=yx[i+];//注意这里,如果某个点i+1既没有人要去,又没有人的起点是它,那么arr[i+1]一定大于wait[i+1],而且yx[i]是可以加上yx[i+2]的,所以要做特判(这个点值20分,题解里有的没有写qwq)说实话应该再来个循环判断的,但是我懒qwq
  36. }
  37. else yx[i]=goal[i];//如果无法影响到i+1,那么造福的人数就只有到达i的人
  38. }
  39. }
  40. for(int i=;i<=n;i++)//选最大
  41. {if(yx[i]>max_yx)
  42. {max_yx=yx[i];
  43. max_i=i;
  44. }
  45. }
  46. if(max_i==)break;
  47. d[max_i]--;
  48. k--;
  49. for(int i=max_i-;i<=n;i++)//简单粗暴的维护
  50. arr[i]=max(arr[i-],wait[i-])+d[i];
  51. }
  52. int sum=;
  53. for(int i=;i<=m;i++)
  54. {
  55. sum+=arr[ck[i].aim]-ck[i].time;
  56. }
  57. printf("%d\n",sum);
  58. }

这两个人轮流来,所以在决策的时候就很麻烦,而且没有后效性。所以我们把A和B的决策算做一步。这样决策就有后效性了。

设每经过一遍决策之后到达的城市与当前所在的城市连一条边,那每个城市只有一条出边,这就是棵平衡树。dalao都说用双向链表什么的,可惜我只见过set。

我们从出发点往上跳,看能否跳到终点,当在每一层最大的边权大于x的时候就不能跳了。这里我们用树状倍增处理。

树状倍增:

设fa[i][j]表示i的第2^j个祖先。max[i][j]=max(i,fa[i][j])表示i到fa[i][j]的最大边权。二分比较。

二分答案+check。(仿佛看见当年跳石头的影子)为什么捏?你看这毒瘤数据范围,又大又圆。

怎么检查?

检查点建立的越接近首都,覆盖的路径就越多。所以我们希望检查点都建立在首都的儿子节点上。

但是有的军队可能不能在t的时间内走道首都的儿子节点,那我们不动它,把所有军队能走道的节点标记下来。每个标记的节点的子树就被控制住了。但如果还有节点没有封住,怎么办?(就像下面这样)

我们先假设军队在建造完成之后还可以移动。每个的剩余移动时间为d[i],让最少的不再移动,让其他的移动到首都。再通过首都移动到没有覆盖住的点。这样我们按照剩余时间排序,看军队是否能覆盖剩余检查点。

思路:最短路。(因为最少时间啊)老师表示这玩意就是n个拼起来不想讲

暴力预处理每个状态,然后跑最短路(如果图不连通,就无解)

我们像上面这样把屏幕分成几个格子,看小鸟能到达哪些格子。

依旧是二分时间+判定。

二分答案后就是考虑树上两个点的距离是否小于某个数。(不加虫洞)(用树状倍增)

来我们加上虫洞。

在不加虫洞时,有些能完成,而有些完不成。要保证都能完成,我们把虫洞放在完不成的路径的交上。(选权值最大那条边)放完之后看能否都能完成。

details:

找交:看路径是否被覆盖n次。我们覆盖路径的时候,因为每次路径的次数要+1,暴力加复杂度就炸了。所以我们用前缀和的方式来整。

空间???真是鬼畜。(玄学)

开a[100]记录???

正解:设

number ,prenumber, count

if(number!=prenumber)count--;

else count++;

if(count==0)prenumber=number;

ans=prenumber;

prenumber是上一个读入的数,number是当前读入的数,重复这个玄学操作一直到最后。

这里的数据保证有解。(因为这个正解算法判不了无解,如果有毒瘤数据就裱出题人好了(小姐姐说的qwq))

首先,你建不出来补图

妈耶我又凉了

如果两个点之间没有边,那么它在补图里有边。如果有边,那在补图里就没有边。

从1开始,把和它没有边关系的点加入队列。一个一个处理队列里面的点。当队空时,就处理完了一个联通块。如果还有没有入队过的点,就从这个点开始,进行相同的操作。直到所有点都入过队。

我们考虑一下优化。用链表。

NOIP 真题选讲的更多相关文章

  1. PJ考试可能会用到的数学思维题选讲-自学教程-自学笔记

    PJ考试可能会用到的数学思维题选讲 by Pleiades_Antares 是学弟学妹的讲义--然后一部分题目是我弄的一部分来源于洛谷用户@ 普及组的一些数学思维题,所以可能有点菜咯别怪我 OI中的数 ...

  2. Noip前的大抱佛脚----Noip真题复习

    Noip前的大抱佛脚----Noip真题复习 Tags: Noip前的大抱佛脚 Noip2010 题目不难,但是三个半小时的话要写四道题还是需要码力,不过按照现在的实力应该不出意外可以AK的. 机器翻 ...

  3. 历年NOIP真题总结

    前言:最近把历年的NOIP真题肝了一遍(还有3个紫题先咕掉了),主要是到1998年的提高组的题.把题目的做题简要思路搁在这儿,一个是为了考前翻一翻,想想自己的哪些思路要梳理的什么什么的,反正怎么说呢, ...

  4. 正睿OI DAY3 杂题选讲

    正睿OI DAY3 杂题选讲 CodeChef MSTONES n个点,可以构造7条直线使得每个点都在直线上,找到一条直线使得上面的点最多 随机化算法,check到答案的概率为\(1/49\) \(n ...

  5. 2019暑期金华集训 Day6 杂题选讲

    自闭集训 Day6 杂题选讲 CF round 469 E 发现一个数不可能取两次,因为1,1不如1,2. 发现不可能选一个数的正负,因为1,-1不如1,-2. hihoCoder挑战赛29 D 设\ ...

  6. NOIP真题索引

    NOIP真题索引 NOIP2019 Day 1 格雷码 括号树 树上的数 Day 2 Emiya 家今天的饭 划分 树的重心 NOIP2018 Day 1 铺设道路 货币系统 赛道修建 Day 2 旅 ...

  7. NOIP真题汇总

    想想在NOIP前总得做做真题吧,于是长达一个月的刷题开始了 涉及2008-2016年大部分题目 NOIP [2008] 4/4 1.传纸条:清真的三维DP 2.笨小猴:字符串模拟 3.火柴棒等式:打表 ...

  8. ZROI 暑期高端峰会 A班 Day5 杂题选讲

    CF469E \(n\) 个需要表示的数,请使用最少的 \(2^k\) 或 \(-2^k\) 表示出所有需要表示的数.输出方案. \(n\le 10^5,|a_i|\le 10^5\). 首先每个数肯 ...

  9. hs-black 杂题选讲

    [POI2011]OKR-Periodicity 考虑递归地构造,设 \(\text{solve(s)}\) 表示字典序最小的,\(\text{border}\) 集合和 \(S\) 的 \(\tex ...

随机推荐

  1. xshell输入字母空格间距变大

    按一下shift+空格(全角/半角转换的快捷键,引起的问题)

  2. idea 社区版本创建javaweb项目 使用jetty

    idea社区版本 创建javaweb项目后使用jetty启动 <dependencies> <dependency> <groupId>javax.servlet& ...

  3. Spring源码解析-核心类之XmlBeanFactory 、DefaultListableBeanFactory

    DefaultListableBeanFactory XmlBeanFactory 继承自 DefaultListableBeanFactory , 而 DefaultListableBeanFact ...

  4. UVA-10462.Is There A Second Way Left(Kruskal+次小生成树)

    题目链接 本题大意:这道题用Kruskal较为容易 参考代码: #include <cstdio> #include <cstring> #include <vector ...

  5. python为什么人们喜欢学习呢?

    软件的质和量. 既有量的积累也有质的区别.继承一定的前人研究基础. 基本上来说,python更加的注重可读性,一致性,可移植性,其中软件的质量也是比较的讲究的. python支持开发的高级重用机制,例 ...

  6. 使用MySQL Workbench进行数据库设计——MySQL Workbench使用方法总结

    本文出自[我是干勾鱼的博客] 转自:https://blog.csdn.net/dongdong9223/article/details/48318877 1 创建Model(设计ER图) 使用wor ...

  7. log.info()传入多个参数的方法

    不知道项目里用的是啥 ** 版本的 log4j 居然不能传入变长参数 logger.info(String.format("%s %s %s", username, feature ...

  8. call apply bind的使用方法和区别

    call 1.改变this指向   2.执行函数    3.传参 var obj={}; function fun(a,b){ console.log(a,b,this); } fun(1,2); / ...

  9. vue中的scope

    在vue文件中的style标签上,有一个特殊的属性:scoped. 当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组件元素. 通过该属 ...

  10. 微信小程序倒计时实现功能

    onLoad: function () {    var that=this;    this.data.intervarID= setInterval(function () {      var ...