这个东西还是应该写写博客的,毕竟IOI
题目连接已给出,直接点击大标题(推荐网络OJ:Universal Online Judge)
IOI2014 Rail
题目有点难看,耐心……
题目是说给出任意两段车站的距离(你只能得知其中的
3(n−1)
对距离)和
0
车站的位置,让你确定每个车站的位置和类型
距离的定义请看题
题目保证
直接说正确的解法(部分分很水请独立思考)
我们会发现:
1.车站
2.离距离某个
C
类型车站最近的车站一定是右方向上最近的
根据以上两条,我们可以按照如下步骤操作:
1.求出所有其它车站到
0
号车站的距离,根据性质2我们可以推出距离最近的站点的位置及类型,将其记为
由此我们可以根据距离关系将剩下的车站分为两类:
1.位于
right
的左方,满足:
dis(0,i)==dis(0,right)+dis(right,i)
2.位于
right
的右方,满足:
dis(0,i)≠dis(0,right)+dis(right,i)
仔细观察发现,此时
0
与
就此我们又可以将
1.位于
0
与
2.位于
0
左方,满足
现在问题剩下:
0
左边与
以
right
右边的为例:
思考:
1.将右边所有车站按照到
0
或者
对于剩下来的车站,我们维护一个
我们每次询问
i
到栈顶
我们可以通过计算得到
dis(0,top)+dis(top,i)
与
dis(0,i)
设
Δ=(dis(0,top)+dis(top,i)−dis(0,i))/2
计算位置
location[top]−Δ
是否合法(在right右边)且该位置上是否存在一个
D
类型车站
如果合法且存在
否则,则说明位置
判断位置是否存在
上面这是干嘛呢?
其实仔细画个图看看就能明白
拿出笔和纸吧(^o^)/~
位置:
0 1 2 3 4 5 6
车站:
C D C D D
编号:
0 1 2 3 4
自己用笔和纸玩一玩就明白
0 左边的车站解法类似
这样我们就在限制条件
时间复杂度:
O(n)
或
O(nlogn)
(
ps:
UOJ上是可以看到其他人的AC代码的
所以不会写的话可以去Orz一下)
IOI2014 Wall
题意很简单:
维护一个区间,支持两种操作:
1、将一段<=k的数全部变成k
2、将一段>=k的数全部变成k
线段树大法好啊!
神马你说你不会线段树打标记∑q|゚Д゚|p?
简单介绍一下:
lazy
标记
意识流一下
lazy
这个词:懒!
把当前对于一个线段区间的操作暂时记录在这,即lazy
待到下一次访问该节点时,将标记操作实施,即向左右子节点下传
(如果不能明白,那就去自行百度下,像”算法竞赛入门经典训练指南”这类良心书上也有讲解)
对于这个题,维护一下标记和最大值、最小值即可
时间复杂度:
O(nlogn)
IOI2014 Game
题意:给定询问点对的顺序,要求构造一张图,使得在所有询问执行完之前,对方无法判断整张图的连通性
两熊孩子玩游戏……
一个比较容易懂的做法
我们考虑一下每个询问
(u,v)
和它们所在的连通块
linku,linkv
若
linku
与
linkv
之间除
(u,v)
这条边以外的所有边都被询问过,则回答存在
否则回答不存在
若存在另一条边
(x,y)
其中
x∈linku,y∈linkv
且
x,y
没有被询问,若此时我们回答
(u,v)
之间存在一条边,此时
linku
与
linkv
已经连通,那么当
(x,y)
这个询问被放在最后时,健佳就输了这场游戏
linku
与
linkv
之间的边数为
|linku|×|linkv|
(|G|表示G的点数)
连通块的维护可以使用并查集维护
唯一要注意的是并查集合并时询问次数的合并
时间复杂度:近似
O(n3)
(其实远远不到)
一个比较容易写的做法
我的天哪!为什么我的快代码1K,人家代码100+B?
#include"game.h"
int a[1510];
void initialize(int) {}
int hasEdge(int u,int v)
{
if (u<v) u=v;
return ++a[u]==u;
}
(恶意缩行其实是不好的行为,小伙伴们不要学习啊╭(╯^╰)╮!)
这这这!这是怎么过的啊(大雾)?
嗯(⊙v⊙),我们来考虑一个这样的东西:树
我们尝试维护:每个点相对与编号比它小的点只有一条边
这样的话,整个图最后一定是一棵树
在最后一条边被询问之前,整个图的连通性是不确定的
时间复杂度:
O(n)
(梅玉:健佳你太赖皮了,再也不和你玩了!)
(健佳:……)
IOI2014 Gondola
题意太长自己看……
Q1缆车序列检查
我们考虑一下原来的序列
1∽n
这个序列可以循环变动
新的缆车可以在任意时刻换下任意一辆缆车
所以我们只需考虑一下最开始的缆车
1∽n
的相对位置是否有错误
嗯对就是这样
那如果最开始的缆车
1∽n
都被换下来了呢?
输出
1
,完毕
(
(
时间复杂度:
O(nlogn)
(排序)
Q2替换序列
根据上面的推论,我们模拟一下每辆缆车换上来的顺序:
若当前缆车存在于
gondolaSeq
中,则将其放在对应位置
否则放在任意一个位置上,满足当前情况下该位置
i
上的缆车与
为了方便起见,我们将这个任意位置定为
max(gondolaSeq[])
所在的位置(即最后一辆缆车的所在位置)
时间复杂度:
O(max(gondolaSeq[]))
Q3替换序列计数
MOD=1000000009
这个比上面两个有技术含量多了
增加了一种基于分治思想的快速计算方法(不是
FFT
而是快速幂……)
(O(∩_∩)O哈哈~我就不行你能把我的头压在键盘上fahsdglebangekjbalgbdska……)
MOD=1000000009
妈呀!
max(inputSeq[])
竟然有
1000000000
,不能模拟了(@之前写了hash的朋友……)
我们将
inputSeq[]
排个序
inputSeq[]
上的数显然只能在最后放在一个固定位置
诶,我们会发现有些缆车先换上来又换下去了,而且答案主要就是他们玩大的!
等等!
在相邻的
inputSeq[]
之间,那些先换上来又换下去了的缆车,对答案的贡献是一样的,每个缆车可放的位置,为当前状态下剩下的未确定的位置个数
快速幂搞搞就A了!
MOD=1000000009
(
ps:
如果不会写的话,可以去膜拜UOJ上其它Orz的代码)
MOD=1000000009,我都写了四遍了你还不取模自己看着办
时间复杂度:
O(nlogn)?
(不知道其实我不会分析……)
Gondola 完结撒花!
IOI2014 Friend
题目意思自己看……
啥?我没看错吧?一般图最大权独立点集不是NP-hard问题么(NP难题请自行百度)?
众所周知,NP-hard问题是没有精确算法的(说不定以后有哪位Orz搞出来了)
(
ps:
谁说的?我有
O(2N)
的枚举!哎呀kasdlgaiognwagkjdn……)
如果你去想最大权独立点集问题,恭喜你掉坑里了!
我们不妨换一个思想:考虑
i
与
这样我们就构成了一颗树
再把不同的连边方式作为不同的边权放在边上
嗯,这应该是树形DP
恭喜你猜中正解!
我们定义:
yes[i]——在以i为根的子树可以选择点i时的最大点权独立集
no[i]——在以i为根的子树不可以选择点i时的最大点权独立集
(
ps:
可以选择
≠
选择)
DP
方法如下:
1.若
i
不可以选择,即与其相连的
2.若
3.若
如果我们之前决策选择过一个编号较小的
I
或
嗯,一个
dp of DP
就解决了!
妈妈你看!人家的AC代码怎么又比我短一截啊?
#include "friend.h"
#define max(a,b) ((a)>(b)?(a):(b))
int G[100005];
int findSample(int N,int F[],int H[],int O[])
{
for (int i=N-1;i;i--)
{
int x=H[i];
if (O[i]==0)
F[x]+=G[i],G[x]+=max(F[i],G[i]);
if (O[i]==1)
F[x]=max(F[x]+max(F[i],G[i]),G[x]+F[i]),G[x]+=G[i];
if (O[i]==2)
F[x]=max(F[x]+G[i],G[x]+F[i]),G[x]+=G[i];
}
return max(F[0],G[0]);
}
(只能说博主自带代码复杂度翻倍的BUFF,具体多少倍看题吧……)
大神:“嗯,很显然,这两个
DP
其实是等价的(ーー゛)”
博主:“我还是太弱了……”
IOI2014 Holiday
题目意思一样自己看nglajksdgnawn……
嗯,第一眼看完:不会o(>﹏<)o……
不过我们会发现,子任务2的起点是固定在最左的
嗯,对于子任务2,一定是一次性从左走到右,然后在路途中玩上几天
枚举走的天数+函数式线段树求区间前k大值之和水过?
啥?函数式线段树是啥?
不会的自行百度吧……(你也可以使用主席树,没什么差别)
简单扯一两句:
假设我们要维护一颗线段树,它支持
ctrl+z
(即还原历史记录)操作,怎么办?
我们可以通过新建节点来代替原先的修改操作,从而实现全信息保存
嗯,由于线段树单点修改每次只会影响一条链的值,改一条链即可
空间复杂度:
O(n+mlogn),n
为序列长度,
m
为操作次数
时间复杂度:
思考:对于其他任务,我们每次一定只存在四种情况:
1、一直向右,路上玩
2、先向右再向左,路上玩
3、先向左再向右,路上玩
4、一直向左,路上玩
我们回过头来看看子任务2
设
r[x]
表示向右边行动
x
天(包括走和玩)所到达的最右城市编号(不是景点数)
显然
我们会发现:
r[x]<=r[x+1]
意识流:当天数增加一天时,我们可以选择在之前的城市中再多玩一天,或者多走一天到达下一个城市
意识流告诉我们,可以数学归纳证明,这里不再赘述
同理,另外三个函数值(向左边行动,向右边行动后折返回出发点,向左边行动后折返回)同样具有单调性
嗯,不错的想法
决策的单调性有什么用呢?
问题转化一下:
函数
r()
的定义域为
[l,r]
,值域为
[a,b]
,且满足单调上升,求
r()
我们定义
mid=(l+r)/2
我们先枚举
[a,b]
求出
r(mid)
的值
(处理值的方法:上面提到过)
利用决策的单调性,递归处理定义域为
[l,mid−1]
和
[mid+1,r]
的函数值
因为决策单调性,两者的值域变为
[a,r(mid)]
和
[r(mid),b]
,即枚举状态的减少
通过计算时间复杂度可知为
O(nlog2n)
我们处理出四个函数的值,再进行各阶段天数的枚举
OK,最后一题就这样A了!
等等,我怎么MLE了?
请注意空间限制:
64M
如果TLE了的话请注意一下你的线段树(少维护一些左右区间范围啊这种没用的东西)
时间复杂度:
O(nlog2n)
嗯,IOI2014完结撒花!