IOI2014题解

这个东西还是应该写写博客的,毕竟IOI

题目连接已给出,直接点击大标题(推荐网络OJ:Universal Online Judge)

IOI2014 Rail

题目有点难看,耐心……

题目是说给出任意两段车站的距离(你只能得知其中的3(n?1)对距离)和0车站的位置,让你确定每个车站的位置和类型C或D

距离的定义请看题

题目保证0车站为C类型

直接说正确的解法(部分分很水请独立思考)

我们会发现:

1.车站x到y的距离==车站y到x的距离

2.离距离某个C类型车站最近的车站一定是右方向上最近的D类型车站

根据以上两条,我们可以按照如下步骤操作:

1.求出所有其它车站到0号车站的距离,根据性质2我们可以推出距离最近的站点的位置及类型,将其记为right。

由此我们可以根据距离关系将剩下的车站分为两类:

1.位于right的左方,满足:dis(0,i)==dis(0,right)+dis(right,i)

2.位于right的右方,满足:dis(0,i)≠dis(0,right)+dis(right,i)

仔细观察发现,此时0与right只可能存在C类型的车站

就此我们又可以将right左方的车站分为两类:

1.位于0与right之间,满足dis(right,i)?dis(right,0)

2.位于0左方,满足dis(right,i)>dis(right,0)

现在问题剩下:0左边与right右边的了

以right右边的为例:

思考:

1.将右边所有车站按照到0或者right排序,最近的一定是D类型的车站

对于剩下来的车站,我们维护一个D类型车站的栈

我们每次询问i到栈顶top的距离

我们可以通过计算得到dis(0,top)+dis(top,i)与dis(0,i)

设Δ=(dis(0,top)+dis(top,i)?dis(0,i))/2

计算位置location[top]?Δ是否合法(在right右边)且该位置上是否存在一个D类型车站

如果合法且存在D类型车站,则说明位置location[top]?dis(top,i)上存在一个C类型车站

否则,则说明位置location[0]+dis(0,i)上存在一个D类型车站,并将其加入栈

判断位置是否存在D类型车站,可以使用二分或者hash

上面这是干嘛呢?

其实仔细画个图看看就能明白

拿出笔和纸吧(^o^)/~

位置:0   1  2   3  4  5  6

车站:C D C      D D

编号:0  1   2       3  4

自己用笔和纸玩一玩就明白

0左边的车站解法类似

这样我们就在限制条件3(n?1)下解决了这个问题

时间复杂度: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,完毕

(ps:容许我吐槽一下子任务1……)

(pps:一定不要在这里使用缆车的hash,不然后果自负)

时间复杂度:O(nlogn)(排序)

Q2替换序列

根据上面的推论,我们模拟一下每辆缆车换上来的顺序:

若当前缆车存在于gondolaSeq中,则将其放在对应位置

否则放在任意一个位置上,满足当前情况下该位置i上的缆车与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与host[i],我们将他们连一条边

这样我们就构成了一颗树

再把不同的连边方式作为不同的边权放在边上

嗯,这应该是树形DP

恭喜你猜中正解!

我们定义:

yes[i]——在以i为根的子树可以选择点i时的最大点权独立集

no[i]——在以i为根的子树不可以选择点i时的最大点权独立集

(ps:可以选择≠选择)

DP方法如下:

1.若i不可以选择,即与其相连的I类儿子可以选择,M与W类儿子不可以选择(为什么M就不能选呢?i不可以选择代表有个与它相连的人被选择,而M类儿子会与其连边,嘣!)

2.若i可以选择并且选择,即与其相连的M类儿子可以选择,I与W类儿子不可以选择(这个很容易理解)

3.若i可以选择但不选择,此时i对i的儿子没有多大影响,我们可以在这里再进行一个dp,这个dp的限制条件如下:

如果我们之前决策选择过一个编号较小的I或W类儿子,就不能再决策徐州呢编号大的M或W类儿子(很显然这两个儿子相连)(注意每个人是按编号顺序以此进入)

嗯,一个dpofDP就解决了!

妈妈你看!人家的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为操作次数

时间复杂度:O(nlogn)

思考:对于其他任务,我们每次一定只存在四种情况

1、一直向右,路上玩

2、先向右再向左,路上玩

3、先向左再向右,路上玩

4、一直向左,路上玩

我们回过头来看看子任务2

设r[x]表示向右边行动x天(包括走和玩)所到达的最右城市编号(不是景点数)

显然x天后我们停留在r[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完结撒花!

时间: 2024-10-11 20:34:12

IOI2014题解的相关文章

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种

8.8联考题解

今天的T1让我怀疑我是不是在做奥赛题--这考的是什么知识点啊这个,会不会用绝对值函数? Evensgn 的债务 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Evensgn 有一群好朋友,他们经常互相借钱.假如说有三个好朋友A,B,C.A 欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元.Evensgn 是个追求简约的人,他觉得这样的债务太繁杂了.他认为,上面的债务可以完全等价为 A 欠C20 元,B 既不欠别人,别人也不欠他.这样总债务规模就压缩到了 

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK)

(leetcode题解)Pascal&#39;s Triangle

Pascal's Triangle  Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 题意实现一个杨辉三角. 这道题只要注意了边界条件应该很好实现出来,C++实现如下 vector<vector<int>> generate(int

2017ZZUACM省赛选拔试题部分题解----谨以纪念我这卡线滚粗的美好经历

写在前面: 其实心里有些小小的不爽又有点小小的舒畅,为啥捏?不爽当然是因为没被选拔上啦,舒畅捏则是因为没被选拔上反而让自己警醒,学长也提点很多很多."沉下去,然后一战成名"学长如是对我说,我很开心.其实这完全算不算是题解,只是我个人的一些小想法而已.而且到现在还有一题不会...让自己长点记性吧. 题目 A :聪明的田鼠 Time Limit: 1 Sec Memory Limit: 128 MB Description 田鼠MIUMIU来到了一片农田,农田可以看成是一个M*N个方格的矩

LeetCode-001题解

此题目摘自LeetCode001 Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.

leetcode题解: Next Permutation

最近还一直在刷leetcode,当然,更多时候只是将题解写在自己的电脑上,没有分享出来.偶尔想起来的时候,就写出来. public class Solution { public void nextPermutation(int[] nums) { if(nums==null||nums.length<=1) return; nextPermutationHelp( nums,0,nums.length-1); } public void nextPermutationHelp(int []nu

HDU 5014 Number Sequence(2014 ACM/ICPC Asia Regional Xi&#39;an Online) 题解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5014 Number Sequence Problem Description There is a special number sequence which has n+1 integers. For each number in sequence, we have two rules: ● ai ∈ [0,n] ● ai ≠ aj( i ≠ j ) For sequence a and sequ

HDU 1045 Fire Net 二分图Bipartite题解

本题可以使用DFS直接爆搜出答案,不过这样类型的题目其实是个二分图的题解. 这个二分图,难不在Hungary算法,而是难在于建图.需要挺高的抽象思维的. 建图: 1 把同一行不被X分开的格子标同一个号码,被X分开的标下一个号码,这样做是为了缩点,不需要把所有的格子都分开标号,而且可以更方便建个更加小的图. 2 同理把同一列的格子标号 3 然后判断相同一个格子的行标号和列标号是有路径的,其他不在同一个格子的都是没有路径的. 4 这样就等于以行标号和列标号作为左右顶点,构建成一个二分图了 然后使用H