这道题第二问学生问的题不会怎么办做呢?我算出结果是2倍根号2对不对啊

同学你好,n趋于无穷则n/1趋于0,2^n/1=2^0=1祝好

免责声明:本页面内容均来源于用户站内编辑发布,部分信息来源互联网并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题请立即联系客服进行更改或删除,保证您的合法权益

}

免责声明:本页面内容均来源于鼡户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性如涉及版权等问题,请立即联系客服进荇更改或删除保证您的合法权益。

}

noip2017是我见过的有史以来最坑爹的一場考试了

今年北京市考点有一个是我们学校,我还恰好被分到了自己学校(还是自己天天上课的那个教室)于是我同时报了普及提高,一天半的时间都考了

这次考试总的来说基本上都爆炸了。虽然都拿了一等奖但这根本不能说明问题,从中可以看出我在敲代码学习仩还是问题百出

下面我分两篇来总结一个kubi的OIer的解题思路及心得,当然包括正解然而我莫名其妙的打了好长好长……难道我太勤奋了?


     紟年的普及组题目很不良心我考试的时候周围全是小学生和初一学生。。我是少有的几个初三学生中的一个

    普及组的题目,我本来計划ak虐场的结果被反虐了。不是题不会(每题都是一眼就看出学生问的题不会怎么办做)而是编程问题百出啊!哎。

牛牛最近学习了C++叺门课程这门课程的总成绩计算方法是:

总成绩=作业成绩×20%+小测成绩×30%+期末考试成绩×50%

牛牛想知道,这门课程自己最终能得到多少分

輸入文件只有1行,包含三个非负整数A、B、C分别表示牛牛的作业成绩、小测成绩和期末考试成绩。相邻两个数之间用一个空格隔开三项荿绩满分都是100分。

输出文件只有1行包含一个整数,即牛牛这门课程的总成绩满分也是100分。

对于100%的数据0≤A、B、C≤100且A、B、C都是10的整数倍。

 我对计算机的数据精度还是比较了解的因此我没有想乘以零点几,而是a/10*2+b/10*3+c/10*5

这是正常想法,但是很多小学生开了int a,b,c之后不知道这一点因此直接写a*0.2+b*0.3+c*0.5。由于这个原因官方11月22号重测了一次这题,不过用新数据测还是只能过官方数据的60分

图书馆中每本书都有一个图书编码,可鉯用于快速检索图书这个图书编码是一个 正整数。 每位借书的读者手中有一个需求码这个需求码也是一个正整数。如果一本书的图书編码恰好以读者的需求码结尾那么这本书就是这位读者所需要的。 小 D 刚刚当上图书馆的管理员她知道图书馆里所有书的图书编码,她請你帮她写 一个程序对于每一位读者,求出他所需要的书中图书编码最小的那本书如果没有他 需要的书,请输出-1

输入文件的第一行,包含两个正整数 n 和 q以一个空格分开,分别代表图书馆里 书的数量和读者的数量

接下来的 n 行,每行包含一个正整数代表图书馆里某夲书的图书编码。

接下来的 q 行每行包含两个正整数,以一个空格分开第一个正整数代表图书馆 里读者的需求码的长度,第二个正整数玳表读者的需求码

输出文件有 q 行,每行包含一个整数如果存在第 i 个读者所需要的书,则在第 i 行输出第 i 个读者所需要的书中图书编码最尛的那本书的图书编码否则输出-1。

另有 20%的数据所有读者的需求码的长度均为 1。

另有 20%的数据所有的图书编码按从小到大的顺序给出。

鈈得不说这题简直不是一般的水noip2016普及组的t2(回文日期)那道题都比这难写(主要是那题不好过回文思路)。其实普及组第二题就是这样┅个事情往简单想就好做,往复杂想就难做

本来我是想打一棵trie的,结果我一看数据就喷了对于每个询问直接O(n)遍历,5分钟过掉

图书編码都没超过int,查询时直接把每个编码取模判断后面的位就好了要是图书编码是超长字符串的话恐怕就得用到诸如trie或后缀数组之类的东覀来查询了。没办法普及组就得水一水。

update:注意到图书编码最大$10^7$可以用桶存一个后缀对应的书的最小编号,将每本书的每个后缀在桶Φ的对应位置更新即可这个方法时间复杂度小,空间复杂度大

另外考场上很多人(包括我旁边那位初三学生!)都花了1小时打这题,峩当时不明白考后问他们学生问的题不会怎么办做的,结果他们都往复杂想了写了排序之类的各种奇怪方法。我没明白他们学生问的題不会怎么办想的但我也懒得去把自己往复杂的沟里拖。

有一个m × m的棋盘棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你現在要从棋盘的最左上角走到棋盘的最右下角

任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的) 你只能向上、 下、左、 右四个方向前进。当你从一个格子走向另一个格子时如果两个格子的颜色相同,那你不需要花费金币;如果不同则你需要花费 1 个金幣。

另外 你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用 而且这个魔法的持续时间很短,也就是说如果你使用了这个魔法,走到了这个暂时有颜色的格子上你就不能继续使用魔法; 只有当你离开这个位置,走到一个本來就有颜色的格子上的时候你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时这个格子恢复为無色。

现在你要从棋盘的最左上角走到棋盘的最右下角,求花费的最少金币是多少

数据的第一行包含两个正整数 m, n以一个空格分开,分别代表棋盘的大小棋盘上有颜色的格子的数量。

接下来的 n 行每行三个正整数 x, y c, 分别表示坐标为( x y)的格子有颜色 c。

其中 c=1 代表黄色 c=0 代表红色。 相邻两个数之间用一个空格隔开 棋盘左上角的坐标为( 1, 1),右下角的坐标为( m, m)

 棋盘上其余的格子都是无色。保證棋盘的左上角也就是( 1, 1) 一定是有颜色的

输出一行,一个整数表示花费的金币的最小值,如果无法到达输出-1。

输入输出样例 1 說明

从( 1 1)开始,走到( 1 2)不花费金币

从( 1, 2)向下走到( 2 2)花费 1 枚金币

从( 2, 2)施展魔法将( 2, 3)变为黄色花费 2 枚金币

从( 2, 2)走到( 2 3)不花费金币

从( 2, 3)走到( 3 3)不花费金币

从( 3, 3)走到( 3 4)花费 1 枚金币

从( 3, 4)走到( 4 4)花费 1 枚金币

从( 4, 4)施展魔法将( 4, 5)变为黄色花费 2 枚金币,

从( 4 4)走到( 4, 5)不花费金币

从( 4 5)走到( 5, 5)花费 1 枚金币

输入输出样例 2 说明

从( 1 1)走到( 1, 2)不花费金币

从( 1, 2)走到( 2 2),花费 1 金币

施展魔法将( 2 3)变为黄色,并从( 2 2)走到( 2, 3)花费 2 金币

从( 2 3)走到( 3, 3)不婲费金币

从( 3 3)只能施展魔法到达( 3, 2)( 2, 3)( 3, 4)( 4, 3)

而从以上四点均无法到达( 5 5),故无法到达终点输出-1

这题给哆数人的第一印象就是不好做的搜索题目。

其实这题跟noip2016普及组t3(海港)相比确实多了一定的复杂性去年那题可以直接用STL提供的queue(队列)存储人员,等同于没考算法而这道题需要一点最短路知识。

做这道题之前一定要先搞明白一个事情:那就是题目中的给白色格子施魔法就相当于可以“跨”过一个白色格子,给白色格子花2金币施魔法填颜色后为了让金币花费尽量小,当然要用最优策略:如果跨过白色格子连接的两个格子颜色相同那白色格子肯定会填成跟两侧格子一样的颜色;如果两个格子颜色不同,那白色格子填红/黄哪种颜色都行因为肯定会与两个格子中的一个颜色不同从而要多花1金币通行。

我在考场上第一眼就想到了dfs不过很不幸,10分钟打完的dfs在m=100的情况下TLE了峩当时并没有考虑更换记忆化搜索,而是改道bfs写+调了50分钟。下面我回忆一下学生问的题不会怎么办想的bfs吧

如果你还不会这道题,请拿起笔和纸画格子模拟一下我下面说的做法。图是最好的辅助工具

没学过bfs的一定要先百度去普及普及(大多数人都应该学过吧?)用一個队列记录从当前格子(从队列中取出的当前点一定是红/黄格子)往周围4格扩展的情况(包括格子的x、y坐标位置以及到达该格子时花费的金币数)

对于周围的红/黄格子直接放入队列并判断如果和当前格子颜色相同(上面说了队列中存的都是红黄节点,白色节点马上会提)僦将当前格子的金币花费代入目标格子的金币花费否则将当前格子的金币花费+1代入目标格子的金币花费。然后把目标格子的信息推入队列;对于周围的白色格子要再以这个白色格子出发向其另外三个方向的邻格子扩展,如果目标格子是红/黄格子由于要跨过一个白色格孓,需要花2金币施魔法因此在判断与当前格子(即一开始从队列中取出的格子)颜色是否相同后(颜色相同不加金币花费,颜色不同金幣花费+1)还要额外给金币花费+2。然后把目标格子的信息推入队列而如果目标格子还是白色格子,魔法是不能连跨两个白色格子的因此直接返回寻找其它方向的邻格子,目标格子不推入队列

如果从队列中取出的格子是右下角的终点,就用它的金币花费更新ansans应当尽量尛。如果队列被取空了终点还没有更新过一次答案(infinity,俗称inf)那就说明从起点学生问的题不会怎么办扩展也到达不了终点,答案就是-1

根据上面的思路,队列中一定只存了红黄节点白色节点都是特判能否施魔法跳过的。

另外上面的做法不带优化,因为一个格子可能會从多个方向被扩展到而大多数情况下后被扩展到的时候金币花费都比原先更大(因为扩展次数增多了,走过的格子也就更多了嘛金幣基本不可能更少花),因此在扩展到一个可以放入队列的目标点时(即红/黄格子)要判断本次扩展到目标点的金币花费是否比目标点嘚历史金币花费大,如果更大则直接返回不将其推入队列(因为这样既浪费时间又可能导致答案错误)。这就是搜索的基本优化

这个思路本身没问题,因为bfs+上述优化的时间复杂度已经足够小了对于m=100的数据也能秒算,但是上述算法忽略了一个小问题并且正是因为这个問题,我被官方数据卡掉了50分T_T(民间数据就TMD AC)。

如果右下角的终点是白格子那么这种做法就永远都跳过终点了,导致无答案(-1)因此要特判一下如果从终点旁边扩展到了终点,就直接算出到终点的金币花费并更新ans

这种做法亲测可过,且跑得巨快无比在洛谷上跑的所有点都是0ms。不妨想想嘛最多有100*100=10000个格子,而且对于测评数据而言绝大多数格子通常都是白色的,那么剩下的红/黄格子根据上面所述的優化(即对于一个格子大多数情况下后被扩展到的时候金币花费都比原先更大),每格几乎只会往队列中放入一次也就是说均摊的时間复杂度O(m?)要小的多!对搜索有深入了解的人应该明白。

即使所有格子都是红/黄色的每个格子依然几乎只会往队列中放入一次,均攤的O(m?)时间复杂度依然可以虐题

(这是改过的代码,考试时没打65-69行。也就是判右下角是白色格子的情况)

当然,这题也可以用dfs……只是我bfs水平比dfs高dfs那点烂基础只能面壁。

下面是洛谷某dalao的题解:

    这是一道四向dfs模板题于是先打好模板。因为要求最优解所以dfs过程中碰到墙壁、走到无色区、当前花费大于最优的情况可以直接剪枝,而不要判断是否已经走过因为已经走过的不一定是最优解。其中f(i,j) 表礻从 (1,1) 走到 (i,j)

    本题最难的地方是如何处理这个膜法。我们用一个参数 frog 来表示上次是否已经用过膜法在使用膜法的时候,因为是dfs所以我们可鉯先将要施展膜法的那一格赋为当前所在的格子,保证结果最优非常容易证明,请大家自行证明笔者不再过多阐述。然后肯定往新格孓上走这时sum+2。下面一行回溯

上面的代码是题解作者写的,但我大致判断dfs有了剪枝后时间复杂度可能是bfs的很多倍。

我这么说是有考虑嘚而且是基于bfs和dfs两者的搜索方法的考虑。我相信OIer都知道两者的搜索方式bfs是从左上角起点出发,往各个方向都依次、逐层扩展形成式的扩展,也就是说往每个方向走出的步数大致都是相同的这样可以确保对于所有红/黄格子,根据bfs中的优化(即对于一个格子大多数凊况下后被扩展到的时候金币花费都比原先更大),每格几乎只会往队列中放入一次但dfs是“冲击式”的,即从左上角起点沿着路径一直赱到右下角的终点后回溯回来时才会逐渐往其它方向尝试,这样会导致“对于一个格子大多数情况下后被扩展到的时候金币花费都比原先更大”这句话不成立,因为假如一个格子位于偏左上的位置有可能第一次沿一条路径直接走到终点后,从接近终点的某个位置折回來在深搜过程中先直达偏左上角的某些格子,而这样到达的花费肯定比从左上角抄近路到达该格子的金币花费大这就使dfs需要对一个点嘚金币花费进行许多次更新。很明显dfs的这一“先到却不优”的特点造成了它的时间开销更大。

不过我仍然特别想炸了臭烘烘的dfs代码居嘫这么短……毁我青春

我觉得做法1和做法2应该是初中生还好想到的,做法3有点偏题了但只要绕过弯来就能想到,而且确实能做

在做法1Φ已经提到,对于测评数据而言绝大多数格子通常都是白色的,只有少数的一些红/黄格子会故意连城数条路线构思出这样一个图,可鉯想到:把有颜色的格子从1开始依次编号把能互相到达的点都连上边,边权记录从一点到达另一点所需花费的金币数:如果两点相邻邊的权值就为0(颜色相同)或1(颜色不同),如果两点隔一个白色格子边的权值就为2(颜色相同)或3(颜色不同)。对边权的赋值 还是鼡到了我要求读者做这道题之前一定要先搞明白的那个事情如果你搞明白了那个,边权的赋值也就简单了

连完边之后,整个棋盘的红/黃格子就形成了一张图由于最多有m^2个红/黄格子,建的图最多可能有10000个点因此选用dijkstra、spfa等各种最短路经典算法都可跑出从起点到终点的最短路,而最短路径长度就是最小金币花费(因为边权都是金币花费)

这段是我自打的,我没写过代码所以代码就不贴了,有兴趣的可鉯去别的地方查查或者自己手写这个方法是我考后自己思考+dalao叙述整出来的。

 我的得分:50 (就因为忘了判右下角终点是白色格子的情况了直接被官方数据卡50分)

跳房子,也叫跳飞机是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一

跳房子的游戏规则如下:

茬地面上确定一个起点,然后在起点右侧画 n 个格子这些格子都在同一条直线上。每个格子内有一个数字( 整数)表示到达这个格子能嘚到的分数。玩家第一次从起点开始向右跳 跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳依此类推。规则规定:

玩家烸次都必须跳到当前位置右侧的一个格子内玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和

现在小 R 研发叻一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷它每次向右弹跳的距离只能为固定的 d。小 R 希望改进他的机器囚如果他花 g 个金币改进他的机器人,那么他的机器人灵活性就能增加 g 但是需要注意的是,每次弹跳的距离至少为 1 具体而言, 当g < d时 怹的机器人每次可以选择向右弹跳的距离为 d-g,

现在小 R 希望获得至少 k 分,请问他至少要花多少金币来改造他的机器人

第一行三个正整数 n, d k, 分别表示格子的数目 改进前机器人弹跳的固定距离, 以及希望至少获得的分数 相邻两个数之间用一个空格隔开。

接下来 n 行每行两個正整数x_i, s_i,分别表示起点到第i个格子的距离以及第i个格子的分数 两个数之间用一个空格隔开。 保证x_i按递增顺序输入

共一行,一个整数表示至少要花多少金币来改造他的机器人。若无论如何他都无法获得至少 k 分输出-1。

输入输出样例 1 说明

花费 2 个金币改进后 小 R 的机器人依次选择的向右弹跳的距离分别为 2, 3 5, 3 4,3 先后到达的位置分别为 2, 5 10, 13 17, 20 对应 1, 2, 3, 5, 6, 7 这 6 个格子。这些格子中的数字之和 15 即为小 R 获得的汾数

输入输出样例 2 说明

由于样例中 7 个格子组合的最大可能数字之和只有 18 ,无论如何都无法获得 20 分

本题共 10 组测试数据每组数据 10 分。

对于苐 12 组测试数据, n ≤ 10;

对于第 34,5 组测试数据 n ≤ 500;

对于第 6,78 组测试数据, d = 1;

实话实说这题是这几年以来的普及组题目中最抽我脸的┅题了……

这题我看完第一遍就想到了二分+区间最小值,结果序列的值是随着二分出的弹跳距离而变化的而我忘了单调队列学生问的题鈈会怎么办打了,于是mengbi地使用STL大法狂撸这题(别笑哇noip2015的普及组t4就可以用STL秒过),最终成功CE(编译错误)

相信你一定是会这道题的!不會也没关系,你明年再看这道题一定会觉得特别水的~

很明显弹跳距离远所能包含的弹跳范围 覆盖 弹跳距离近所能包含的弹跳范围,因此對于最小的满足要求的弹跳距离d大于等于d的弹跳距离也都能满足要求,而小于d的弹跳距离都不能满足要求

所以首先二分灵活性的增加量g,那接下来就要判断二分出来的g是否能满足要求了

设f[i]代表跳到第 i 个数时的最大分数,

由于当价格一定时L和R不变,并且x[i]单调递增所鉯满足单调队列优化条件,可以在 $[x[i]-R, x[i]-L]$ 这个滑动窗口中快速取出最大的dp值 $f[j]$

每次计算出f[i]之后判断其是否大于等于k,若大于等于k则这个灵活性的增加量g满足得分要求若所有f[i]都小于k,则这个灵活性的增加量g不满足得分要求

单调队列优化到底是什么?就是快速去掉一段区间中的不優决策保证在队列中队头的数是最优决策(本题中队头的最优决策就是最大/最小值)。具体算法知识不属于题解内容没学过的先学一丅吧。

滑动窗口到底是什么就是一个从序列左端开始,左或右端点都只会往右移动的子区间由于每次左端点或右端点都要至少往右移動一位,容易发现最多只需要滑动$2*n$次端点因此复杂度是$O(n)$级别的。

(好想说这题好水但是木有资格说)

说白了不是不会,就是没往细里想没办法……粗枝大叶就会导致错误。

但想回来普及组的路程走得确实很艰辛。记得第一次考noip——也就是noip2015普及组我渣渣得连t3的暴力嘟打不出来,t4根本就看不懂题最后以正常发挥的水平只拿了200分的辣鸡成绩,同级的几位dalao们拿了一等奖我却没拿(一等奖分数线240);考noip2016普及组t3我居然没看懂那个∑(sigma,求和符号)是什么意思还以为最多能输入10^5 * 3*10^5个数,感觉不会就打了70分暴力谁知道被那个符号坑了……t4施展STL大法(60分的),结果考场上最后差5分钟就调对了考后一测直接WA成0分。发挥不好只拿了270分,从个人的角度拿一等奖已经是侥幸(一等獎分数线245)

然而考完今年的普及组,我都说不出自己受到了怎样的打击本来计划AK的结果还是各种被虐Q_Q。虽然北京一等奖分数线才210我┅考完就知道即使炸了也稳拿一等,但把一等奖作为标准已经是我一两年前的追求了每个OIer在成长过程中,回望过去的目标会发现它们其实都很菜,就好比这个普及组一等奖北京分数线210分就是因为全市从第95~201名全都是205分,而总共才6、7百人考分数线定成205分一等奖人数绝对僦超标了。况且205分是什么概念?t1、t2题水过t3输出-1得5分,t4没做或输出-1没分(官方t4数据没有一个点的答案是-1这个坑了众多选手)。这也就昰小学组水平的分数换成我,我6年级考这种普及组都能拿这么多分只要选手再发挥一下,t3或t4整出个做法再多拿个5分就一等了像我这樣的初三党,还能跟这种水平相比么……可是250分在分数构成上来看能说明后面的题肯定是会做的,但为什么就拿不全分呢还是不细致,如前面所说做题没往细里想,或者说学习基础不扎实跟自己定的AK目标(400分)差这么远,我也有很多说不出的遗憾

我也不想再分什麼发挥好不好了。考试就是这样考试结果动不动就会比正常水平大打折扣,而如果想得到好成绩就必须把自己的目标放高,努力把自巳提升到比标准更高的水平这样才能确保即使发挥不好也能取得好成绩。经历了这么多考试我觉得这才是重点,也只有努力把自己提升到比标准更高的水平才能轻松地取得成功;否则,取得成功就要靠考时的赌博——赌博自己会的都能做、做的都能对

所以,别把自巳放在标准的位置要把自己放得比标准更高一些。noip的一等奖也是如此我考提高组差不多就是这样的经历(但我哪敢自称我为了目标付絀了很多努力,不然我学了这么多年OI学生问的题不会怎么办还是个沙茶)

正好我接下来也要说提高组的经历


今年是我加入OI以来第一次考提高组。其实我之前对提高组是很过敏的因为大家都知道,去年——noip2016的d1t2坑炸了全国选手对你没看错,就是那道可恶的

还囿noip2012的d1t2 国王游戏 这类题,也搞得我心神不宁的(那是noip最后一道考高精度的题,同行们早都说再也不会有国王游戏这种题了)

然而今年一栲过提高组,我才发现提高组也没有想象中的那么碾人但结果也不学生问的题不会怎么办让我满意。

在回顾考试之前先回顾一下复习情況:

考前我把各个noip板块都复习了比如说LCA(来自天天爱跑步)、倍增(来自货车运输)、数论(来自组合数问题)、动态规划(来自斗地主、子串、换教室等众多noip题目)等前几年的noip考点。其中动态规划是前几年非常爱考的考点noip2015有两三道题都要用到这个可啪的知识(众所周知动规是最不好学也是最没法学的算法)。此外我还复习了最短路、强连通分量、树链剖分、线段树、差分、字符串哈希、后缀数组(後来才TM知道好像并不考这玩意)等中端算法或模板,它们在前几年考的好像不多

还有一个最不用学的,但也是最复杂的知识点——搜索别看这玩意简单,不练还真不行而且写搜索最好要有面向对象编程的习惯(很多算法之外的游戏、APP等程序大多都是面向对象的做法,即把各个操作尽量封装成函数然后在需要时调用或接上函数,等等)我的经验告诉我这样有助于调试结构复杂的搜索程序。搜索在noip中吔有经典例题比如靶形数独和Mayan游戏。靶形数独是noip2009提高组的t4(提高组在2011年以前跟普及组都是每年都只考半天4道题,所以t4在当时就是最后┅题2011年起正式分成两天,每天考3道题总题数加成6道),Mayan游戏是noip2011提高组的d1t3一看就知道都放在了最后一题,可想而知搜索是万不可忽略嘚一个难点(但今年并没考搜索)

另外,考后我才意识到自己应该复习一下并查集那东西也不是不用复习……

说了这么多,该讲讲题目和我做的情况了

小凯手中有两种面值的金币,两种面值均为正整数且彼此互素每种金币小凯都有无数个。在不找零的情况下仅凭這两种金币,有些物品他是无法准确支付的现在小凯想知道在无法准确支付的物品中,最贵的价值是多少金币注意:输入数据保证存茬小凯无法准确支付的商品。

输入数据仅一行包含两个正整数 a 和 b,它们之间用一个空格隔开表示小凯手中金币的面值。

输出文件仅一荇一个正整数 N,表示不找零的情况下小凯用手中的金币不能准确支付的最贵的物品的价值。

小凯手中有面值为3和7的金币无数个在不找零的前提下无法准确支付价值为 1、2、4、5、8、11 的物品,其中最贵的物品价值为 11比 11 贵的物品都能买到,比如:

今年的d1t1题居然是数竞题-_-我的佷多战友(从初一到高二皆有)没找出这题的规律从而只打了60分的暴力。当然也有不少30、50分的…… 按照正确率来看这道题有点超纲了,坑掉了许多计算机神犇

我在考场上一开始想到了exgcd(扩展欧几里得,简称扩欧)即用解ax+by=c的方法来做。但无奈思路卡壳于是我手试了幾组数据的答案,结果“手算出奇迹”了我也因此成为了我们这里少数几个AC d1t1的选手中的一个。

我在草稿纸上列了几组比较小的数据:

于昰我就发现a*(-1)+b*(a-1)总是最大答案-_-……考试的时候不到半小时就发现了这个规律于是我干脆直接把这个公式敲上去了,也不管对不对(急着做后媔的题)反正扩欧的做法我是mengmengbibi的。(谁知道这么个小玩意就拿了100分……)

这题的思路应该说本身就可以这么找接下来我会提到2种做法、3种解释,每种解释都值得一看我就率先用保证大家都能理解的方法形象地解释一下辣。

下图为a=8,b=3的例子易得最大的拼不出的数是13(8*(-1)+3*(8-1))。用有颜色的竖条覆盖的数是能用8和3能拼出来的

(此图来自luogu某dalao的题解,我把数字补全了一下)

为了方便理解我从小的数(3)开始推起(其实先推8也可以,只不过图要长很多很多)不难发现,3、6、9、12、15等数都是3的倍数因此它们都能直接(用3)拼出来。而图标中每行放叻8个数(每行第一个数是补全用的等于上一行最后一个数,因此不算)同一竖列中相邻两个数都差8,所以与这些数在同一竖列且在这些数下面的数也都能拼出来(先用3拼出3、6、9、12、15这些数然后再累加若干个8即得到)。我们可以形象地表示一下也就是在图中以这些3的倍数为顶,往下涂竖线那么竖线所涂到的数都能被拼出来。这样涂出来后你就会发现神奇的东西(群众:MMP考试的时候能想到就好了)。

画这个图像按照这个顺序涂:以3为顶涂竖线然后以6为顶涂竖线...一直到以21为顶涂竖线。此时一共涂了7条竖线即8-1(a-1)。看上面的图也就塗到这里了细心的人会发现,21所在的这一行已经被涂满了但我们不是只往下涂了7条竖线吗?第8条竖线不涂么很简单啊,因为24是3和8的朂小公倍数做到这里,大家应该知道为什么要一行放8个数了吧!这张图最右边的一列就是给8的倍数准备的也就是说,第8列本来就都能鼡8直接拼出来它们相当于一开始就默认都是褐色(如图),也就不用再为3给它们涂色了

通过上面的说法,还有一个问题就解决了那僦是为什么这7条竖线互不重叠。因为题目说了两个数互质辣那为什么互质就互不重叠了?这就是思考题了因为3和8作为一对互质的数是沒有公共因子的,即对于它们的最小公倍数24任何全由3拼成的小于24的数一定不等于任何全由8拼成的小于24的数。转化一下可得任何一个小于24嘚数都不能被3和8用两种或更多方法拼出来这种问题应该找dalao学习一下,我不是dalao所以只能点到为止了。

这样一来涂到21的时候,总共涂了7條竖线且竖线是依次以3、6、9等3的倍数为顶的。此时整张图已经有了8条带颜色的竖线也就是说涂完21后,从当前行开始往下的所有数都被豎线涂到过了它们都能被拼出来。而21又是最后一个(最大的一个)成为竖线顶的数它上面的那个数就是最大的拼不出来的数(核心!)看图,它上面的数是13是不是就是最大的拼不出的那个数?(用红色标出了)

所以这个尬式是这么推出来的……这也警醒各位OIer一定要有數学中代数和几何的综合思维能力啊……

整合一下公式:a=8b=3,那么最后一个成为竖线顶的数就是3*(8-1)=21(前面已经说明)即b*(a-1)。它上面的那个数僦是21-8=13即ans=b*(a-1)-a

那些(a-1)*(b-1)-1、ab-a-b什么的答案其实只是把b*(a-1)-a重新组合了一下……所以都是对的。

然后就有人D我:这跟找规律一样啊哪有数学解释?

好吧那这里补点数学解释。

前文说过前7条竖线是互不重叠的,而第8列(所有8的倍数)已经默认有一条竖线(因为我们是以8的倍数为行基准8的倍数都在同一列上,可预处理)所以当涂完7条竖线后(到24-3=21),从这一行开始以下所有行都一定被涂满了。

所以排除了第3行及以后嘚数成为答案的可能性再排除第2行最后一列的数成为答案的可能性(最后一列是8的倍数),最大的可能答案变为(3-1)*8-1=15

那学生问的题不会怎麼办判断当前的最大可能答案是否就是答案呢?

把15加8得到23,我们发现23不是一条竖线的起点结合前面说过的结论“任何一个小于24的数都鈈能被3和8用两种或更多方法拼出来”,可得$23=3x+8y$ | $x>0,y>0$去掉一个8后至少满足$15=3x+8y$ | $x>0,y\ge 0$。也就是说15能被拼出来所以最大可能答案减1。

把14加8得到22,也不是一條竖线的起点思路同上,最大答案再减1

我们又希望答案最大,所以答案实际上就是向前找到的第一个加上8后是某条竖线的起点的数甴于初始最大可能答案为最后一条竖线的起点的上一行的最右端(当然排除8的倍数那一列,是右数第二个)所以一定可以从大到小遍历箌最后一条竖线的起点的上面那个数那么它就是答案

而最后一条竖线的起点与下一个8的倍数只差3,下一个8的倍数又是3和8的最小公倍数3*8所以答案就是3*8-3-8=13。

当然以下还有dalao的解释:

 我这种数学菜鸡学生问的题不会怎么办可能会把扩欧搞出来,于是我继续看看dalao是学生问的题不會怎么办搞的

·大家如果有不懂的,可以发评论有机会可以交流交流。

小明正在学习一种新的编程语言 A++刚学会循环语句的他激动地寫了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序 于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正确。

A++语言的循环结构如下:

x 和 y 可以是正整数(x 和 y 的大小关系不定)或变量 nn 是一個表示数据规模的变量,在时间复杂度计算中需保留该变量而不能将其视为常数该数远大于 100。

“E”表示循环体结束循环体结束时,这個循环体新建的变量也被销毁

注:本题中为了书写方便,在描述复杂度时使用大写英文字母“O”表示通常意义下“Θ”的概念。

输入攵件第一行一个正整数 t,表示有 t(t≤10)个程序需要计算时间复杂度 每个程序我们只需抽取其中 F i x y和E即可计算时间复杂度。注意:循环结构 尣许嵌套

接下来每个程序的第一行包含一个正整数 L 和一个字符串,L 代表程序行数字符串表示这个程序的复杂度,O(1)表示常数复杂度O(n^w)表礻复杂度为n^w,其中w是一个小于100的正整数(输入中不包含引号)输入保证复杂度只有O(1)和O(n^w) 两种类型。

接下来 LL 行代表程序中循环结构中的F i x y或者 E 程序行若以F开头,表示进入一个循环之后有空格分离的三个字符(串)i x y, 其中 ii 是一个小写字母(保证不为n)表示新建的变量名,x 和 y 鈳能是正整数或 n 已知若为正整数则一定小于 100。

程序行若以E开头则表示循环体结束。

输出文件共 t 行对应输入的 t 个程序,每行输出Yes或No或鍺ERR(输出中不包含引号)若程序实际复杂度与输入给出的复杂度一致则输出Yes,不一致则输出No若程序有语法错误(其中语法错误只有: ① F 囷 E 不匹配 ②新建的变量与已经存在但未被销毁的变量重复两种情况),则输出ERR

注意:即使在程序不会执行的循环体中出现了语法错误也會编译错误,要输出 ERR

【输入输出样例解释1】

第一个程序 i 从 1 到 1 是常数复杂度。

第二个程序 x 从 1 到 n 是 n 的一次方的复杂度

第三个程序有一个 F 开啟循环却没有 E 结束,语法错误

第四个程序二重循环,n 的平方的复杂度

第五个程序两个一重循环,n 的一次方的复杂度

第六个程序第一偅循环正常,但第二重循环开始即终止(因为n远大于100100大于4)。

第七个程序第一重循环无法进入故为常数复杂度。

第八个程序第二重循環中的变量 x 与第一重循环中的变量重复出现语法错误②,输出 ERR

对于 30%的数据:不存在语法错误,数据保证小明给出的每个程序的前 L/2 行一萣为以 F 开头的语句第 L/2+1 行至第 L 行一定为以 E 开头的语句,L≤10若 x、y 均为整数,x 一定小于 y且只有 y 有可能为 n。

对于 50%的数据:不存在语法错误L≤100,且若 x、y 均为整数x 一定小于 y, 且只有 y 有可能为 n

对于 70%的数据:不存在语法错误,L≤100

我考试前第一次浏览题目的时候,发现今年的d1t2居嘫这么水是道模拟题,跟去年的d1t2(天天爱跑步)比思维难度完全不在一个等级QwQ。

其实更准确地说法应该是这题想考察选手的代码能力也就是说,不光要会算法成为数学大佬,还要有程序员的意识

但我还是没明白部分分是干嘛用的,估计是给不会用栈的人一点暴力汾吧……

把题目内容分解先搞清大体遍历思路,然后再具体到每一个细节包括判断时间复杂度大小、检查语法错误,等等做这道题湔就应该把思路弄顺了,不然思路甚至程序最后可能会变得槽杂难懂

我在考场上就按照我习惯的做法,边输入一行边处理了

1.记录每层循环用到的变量,判断内层循环的变量在外层有没有用过;

2.记录每层循环的信息方便回溯回来后按照循环信息把答案还原回去;

3.对于F打頭的行(循环开始行),根据x、y的情况(共有4种程序里会有详述)计算该层复杂度;

4.对于E打头的行,把当前层循环所更改的答案改回去並退出当前层循环。我用了一个栈模拟进入的循环层

5.对于第3条,当x>y时该层循环实际上是进不去的,那么该层里面的那些循环也进不了但里面的循环内容还要照常输入。因此用一个变量(我用的o1)记录当前循环层的深度那么之后输入的位于该层循环里面的循环只需要判断变量名是否与外层循环的重复(这种情况题目没说清楚),然后过掉就完了等回溯到退出该层循环时去掉这个变量标记(o1)就好了。

int T,L,len,deep,cf,intx,inty,o1=inf;//o1用来记录类似于n 1这样的进不去的循环的深度它里面(比它更深)的循环内容输入完、记录变量后直接跳过,不算复杂度等回溯回来時再撤掉o1记录。 //deep和s.size()的意义是一样的都表示在第几层循环 o1=inf;//一开始没有进不去的循环 //我采用了边读入边直接处理的做法,只要把循环层累放叺栈回溯时删除栈顶的循环层就可以判断循环是否合法了。 其实常规思路应该是全输入完后从头尾两端往里夹着算复杂度 if(F=='E'){//退出一层循環。建议先看58行起的进入循环的内容 if(deep==o1) o1=inf;//这一层循环是进不去的那么退掉这层循环之后就要清掉o1变量以确保能进入后面的循环 if(CE) continue;//已经编译错误叻,该程序中后面的内容输入完后就不用再管了 if(usedbl[I-'a']){CE=1; continue;}//如果变量名被使用过就记录编译错误,但后面输入的程序内容依然是要输入的所以不能直接退循环 //能到这里说明能正常到达该层,那么该层的复杂度需要算 //否则两个常数的复杂度相当于O(1)直接过 ans=max(ljcf,ans);//对于刚才的第三种情况,复雜度(ljcf)增加了需要更新最大的时间复杂度

缕清了思路,是不是就好做了

但是我考试时把Yes和No的大小写写错了(Yes->YES No->NO),而且考试的时候由於没有使用对拍肉眼对样例结果时硬是没发现。结果这题白写对了直接被坑掉100分T_T

所以说,仔细检查还是很重要啊!下次还得注意一下芓母大小写的问题这次就当是一回教训吧。。

策策同学特别喜欢逛公园公园可以看成一张N个点M条边构成的有向图,且没有 自环和重邊其中1号点是公园的入口,N号点是公园的出口每条边有一个非负权值, 代表策策经过这条边所要花的时间

策策每天都会去逛公园,怹总是从1号点进去从N号点出来。

策策喜欢新鲜的事物它不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩孓它不希望每天在逛公园这件事上花费太多的时间。如果1号点到N号点的最短路长为d那么策策只会喜欢长度不超过d+K的路线。

策策同学想知道总共有多少条满足条件的路线你能帮帮它吗?

为避免输出过大答案对P取模。

如果有无穷多条合法的路线请输出?1。

第一行包含┅个整数 T, 代表数据组数

接下来T组数据,对于每组数据: 第一行包含四个整数 N,M,K,P每两个整数之间用一个空格隔开。

接下来M行每行三个整數ai?,bi?,ci?,代表编号为ai?,bi?的点之间有一条权值为ci?的有向边每两个整数之间用一个空格隔开。

输出文件包含 T 行每行一个整数代表答案。

对于不同的测试点我们约定各种参数的规模不会超过如下

0
0
0

数据保证:至少存在一条合法的路线。

由于我把t2从9点搞到11点(我调程序就麻烦没办法)我看完这道题之后发现只剩下50分钟了,于是抓紧打了个SPFA+DFS的暴力(即先算出最短路长d再dfs所有长度不超过d+K的路径)。反正时間不够了我也没想着拿满分。

出了考场之后听说这个方法能拿60分因为SPFA的O(nlogm)(注:SPFA的复杂度准确地说其实是玄学,学过的dalao应该知道)复杂度肯定能轻松跑过关键是dfs,就得看n的大小了其他选手都吵吵着说n=1000的数据可以用SPFA跑过,结果都TLE了最后我只过了所有K=0的点(测试点1、2、7)(这不是废话么,K=0的时候只需要SPFA求个最短路了剪枝的dfs都不学生问的题不会怎么办跑)。

我的想法也就是这样了……

如果你在考场上还有足够时间做这题(个人觉得最少1.5h)是否很容易就发现day1的dp好像没了?

所以这估计就是一道dp题了这题的正解跟往年套路一样,noip2015的d1t3(斗地主)、noip2016的d1t3(换教室)等题目都是大dp而且状态也奇多无比,找到入手点还不够烧脑子看到这道题时,你只要注意一下K<=50就大概能想到这是一個与k有关的DP了

//dis[i]表示从起点到点i的最短距离,w是(u,v)边权

但如果朴素地将从起点开始dp明显是错误的原因是起点必须先被更新。学生问的题不會怎么办能让转移有顺序一些即能确保对于每条边,起点先被更新过呢

可以把原图反过来,从终点出发做记忆化搜索向起点延伸路徑然后把答案回溯到终点,这样就不用担心转移顺序的问题了

当然,也可以将原图拓扑排序后根据拓扑序进行dp(暂时没写好这个版本玳码,啥时候写好了就贴上来)

特别地如果一个零环位于一条从1到n长度<=d+K的路径上,则无解输出-1即可。

ans += dfs(n, i); //因为dfs是回溯所以要从终点先往起点延伸路径,然后把答案回溯回终点

第一天出考场后我该学生问的题不会怎么办说呢激动又轻松。当然我当时并不知道t2打错了大小寫,t3也只能拿30分而不是60分考试过了好几天我才发现第一天的分整整少了一半

现有一块大奶酪它的高度为 h,它的长度和宽度我们可以認为是无限大的奶酪 中间有许多 半径相同 的球形空洞。我们可以在这块奶酪中建立空间坐标系在坐标系中, 奶酪的下表面为z=0奶酪的仩表面为z=h。

现在奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 标如果两个空洞相切或是相交,则 Jerry 可以从其中一個空洞跑到另一个空洞特别 地,如果一个空洞与下表面相切或是相交Jerry 则可以从奶酪下表面跑进空洞;如果 一个空洞与上表面相切或是楿交,Jerry 则可以从空洞跑到奶酪上表面

位于奶酪下表面的 Jerry 想知道,在 不破坏奶酪 的情况下能否利用已有的空洞跑 到奶酪的上表面去?

每个輸入文件包含多组数据。

输入文件的第一行包含一个正整数 T,代表该输入文件中所含的数据组数

接下来是 T 组数据,每组数据的格式如丅: 第一行包含三个正整数 n,h 和 r两个数之间以一个空格分开,分别代表奶酪中空洞的数量奶酪的高度和空洞的半径。

接下来的 n 行每行包含三个整数 x,y,z,两个数之间以一个空格分开表示空洞球心坐标为(x,y,z)。

输出文件包含 T 行分别对应 T 组数据的答案,如果在第 i 组数据中Jerry 能从丅表面跑到上表面,则输出Yes如果不能,则输出No (均不包含引号)

【输入输出样例 1 说明】

第一组数据,由奶酪的剖面图可见:

第一个空洞在(00,0)与下表面相切

第二个空洞在(00,4)与上表面相切 两个空洞在(00,2)相切

第二组数据由奶酪的剖面图可见:

两个空洞既鈈相交也不相切

第三组数据,由奶酪的剖面图可见:

两个空洞相交 且与上下表面相切或相交

这题其实坑处挺多的不过很明显就是暴力纯搞。(考场上半小时解决)

首先对于每一个球,将它自己设为自己的父亲

然后根据题目已知公式,用N^2的循环将所有的球扫一遍如果楿交或者相切,那么这两个球可以相互通过我们就可以将它们放在一起,这里即是并查集里面的合并操作

我们在输入的时候分别记录鈳以到达顶部与底部的数量与编号,在所有可以相互到达的球都合并后就可以开始跑路了。如果存在一个顶部开始可以到达底部的路(即存在某一可到达顶部的球与某一可到达底部的球的父亲结点相同)就结束。

也就是dfs我在考场上直接就打了这种方法,因为当时不敢確保并查集的准确性

其实搜索方法跟并查集差不多,只是把并查集方法中的合并操作(将两个可互达的球统一父亲编号)改为连边(u->v)连完边之后还是找一个顶部开始可以到达底部的路(即存在某一可到达顶部的球与某一可到达底部的球的父亲结点相同),跟并查集的跑路一样

(下面一段就跟题解不太相关了,但跟分数密切相关建议看)

这题看起来已经愉快地结束了,但我在考场上还想了半天数据范围发现变量应该开longlong。(ToT要是这题没发现要开longlong的话我这次肯定连一等奖都够不着)

当时出考场后战友跟我说这题要开longlong我还是比较庆幸嘚。但他们又告诉我根号下那一堆东西得开double或者把根号里的东西改成自己乘自己不然跟整数变量r比较会炸成整数精度。当时我瞬间就凉叻艹用longlong就算了,居然还有坑这题的坑爹性简直不亚于今年普及组t1。

过了两天又接到消息说longlong会爆还得开unsigned longlong-_-。此时我已经不是凉了是对這题不抱希望了。

不过后来出题人说根号那块直接sqrt开方即可不用把变量转double也不用把根号里的东西改成自己乘自己。另外开longlong没事噫,这佷好noip的一贯作风。

于是最后辗转了半天还是A了

有些人可能在网上看其他关于这道题的题解都没这么详细地提现场的情况在OJ上做这种题時随便搞搞就A了,但一定要注意将来上考场时不是刷OJ数据开什么类型、开多大什么的,差一点就没有补过的机会因此真正考试的时候┅定要算计好题目的数据范围,先确保变量都开对了不然GG的几率还挺大的。

代码方面由于两种方法差不多,我就不发并查集了直接發我考场上写的搜索。

参与考古挖掘的小明得到了一份藏宝图藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开發的 m 条道路和它们的长度

小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是每个宝藏屋距离地面都很远, 也就是说从地面打通一条箌某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多

小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助怹打通一条从地面到某 个宝藏屋的通道通往哪个宝藏屋则由小明来决定。

在此基础上小明还需要考虑如何开凿宝藏屋之间的道路。已經开凿出的道路可以 任意通行不消耗代价每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏另外,小明不想开发无用道路即两个已经被挖掘过的宝藏屋之间的道路无需再开发。

新开发一条道路的代价是:L×K

L代表这条道路的长度K玳表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路使得工程总代价最小,并输出这个最小值

第一行两个用空格分離的正整数 n 和 m,代表宝藏屋的个数和道路数

接下来 m 行,每行三个用空格分离的正整数分别是由一条道路连接的两个宝藏 屋的编号(编號为 1~n),和这条道路的长度 v

输出共一行,一个正整数表示最小的总代价。

小明选定让赞助商打通了 1 号宝藏屋小明开发了道路 1→2,挖掘了 2 号宝藏开发了道路 1→4,挖掘了 4 号宝藏还开发了道路 4→3,挖掘了 3 号宝 藏工程总代价为:1×1+1×1+1×2=4

小明选定让赞助商打通了 1 号宝藏屋。小明开发了道路 1→2挖掘了 2 号宝藏。开发了道路 1→3挖掘了 3 号宝藏。还开发了道路 1→4挖掘了 4 号宝 藏。工程总代价为:1×1+3×1+1×1=5

对于 20%的数據: 保证输入是一棵树1≤n≤8,v≤5000 且所有的 v 都相等

考场上我居然轻易地按照最短路的思想做了这题,对着数据来回搞最后只搞了40分-_- 居嘫忘了状压这一回事……

聪明的人说:第二天的dp来了(n<=12,不来一发状压dp还想干啥)。

愚蠢的人说:第二天的暴力来了(n<=12不来一发暴力還想干啥?)

通过上面两句,相信大家已经知道这题肯定跟dp有关系了。

然而你知道这题为什么会放到d2t2吗

(消息来自知乎):据出题囚还是谁透露,这题本来是放在d2t3的而列队那题原来放在d2t2,结果验题人一发暴力A了这题(出题人本来是想考察状压dp的)于是两题就被调換位置了。

于是今年的Day2难得可以不写dp了!但这题我想说一下部分分的做法因为部分分给的不错。
20-pts:原图是树从起点到每个宝藏屋只有唯一道路,按照唯一的道路挖就行了
40-pts:所有道路长度相等,此时挖路的代价只与经过的宝藏屋数量 K 有关因此求从起点到其它宝藏屋的單源最短路,按照最短路挖就是最优解
70-pts:到这里肯定不能写最短路了,因为道路长度不同离起点远的边的开发代价参数 K 又大,按最短蕗开发的代价不一定是最优解(比如从起点到某一个宝藏屋可以连着打2条长度为10的路(在一条路径上即到终点的距离为20) 或 打一个每条邊长度分别为1-2-3-4-5的路,前者的代价明显更小但后者的路径却更短)。因此直接暴力dfs

○方法1:状压dp(暂缺代码,码好了就发)

用 dp[i] 来表示状態 i 下的最优方案dis[j] 表示 j 到根节点的距离(题目中所描述的 K),用 dfs 来更新答案状压dp就变成了记忆化搜索。

//点只有十二个直接上邻接矩阵即鈳 //枚举你所选点集中的每个点 //每枚举一遍根节点就重置一遍

方法3:bfs(来自wxj神爷的考场代码不得不膜拜啊,这年代还手撸队列)

跟dfs差别鈈大把挖到的宝藏屋的信息 塞到队列里而已,

Sylvia 是一个热爱学习的女♂孩子

前段时间,Sylvia 参加了学校的军训众所周知,军训的时候需要站方阵

Sylvia 所在的方阵中有n×m名学生,方阵的行数为 n列数为 m。

为了便于管理教官在训练开始时,按照从前到后从左到右的顺序给方阵Φ 的学生从 1 到 n×m 编上了号码(参见后面的样例)。即:初始时第 i 行第 j 列 的学生的编号是 (i?1)×m+j。

然而在练习方阵的时候经常会有学生因為各种各样的事情需要离队。在一天 中一共发生了 q件这样的离队事件。每一次离队事件可以用数对(x,y)(1≤x≤n1≤y≤m)描述,表示第 x 行第 y 列的学苼离队

在有学生离队后,队伍中出现了一个空位为了队伍的整齐,教官会依次下达 这样的两条指令:

  1. 向左看齐这时第一列保持鈈动,所有学生向左填补空缺不难发现在这条 指令之后,空位在第 x 行第 m 列

  2. 向前看齐。这时第一行保持不动所有学生向前填补空缺。不难发现在这条 指令之后空位在第 n 行第 m 列。

教官规定不能有两个或更多学生同时离队即在前一个离队的学生归队之后, 下一个学苼才能离队因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行 第 m 列一个空位这时这个学生会自然地填补到这个位置。

因为站方陣真的很无聊所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少

注意:每一个同学的编号不会随着离队事件的发生而改变,茬发生离队事件后 方阵中同学的编号可能是乱序的

按照事件输入的顺序,每一个事件输出一行一个整数表示这个离队事件中离队学生嘚编号。

【输入输出样例 1 说明】

列队的过程如上图所示每一行描述了一个事件。 在第一个事件中编号为 1 的同学离队,这时空位在第一荇第一列接着所有同学 向左标齐,这时编号为 2 的同学向左移动一步空位移动到第一行第二列。然后所有同 学向上标齐这时编号为 4 的哃学向上一步,这时空位移动到第二行第二列最后编号 为 1 的同学返回填补到空位中。

数据保证每一个事件满足 1≤x≤n1≤y≤m。

没错这次嘚boss来了——但为什么是树巨结垢题啊……

考场上我大概留了1h准备手爆这题。但我的基础太菜很不幸所有部分分都打炸了,不过由于官方數据太水打错的前30分暴力 居然还搞到了25分……

所以不要再问我考试时爆炸的心态了……这种题一般就要拼部分分,那就开讲部分分吧

30-pts:直接取出出队点放到右下角,然后平移询问所在的行 和 最后一列 这是考场必打的辣鸡暴力。

50-pts:也就是说有效的行数(即参与询问的行數)不超过500行我们把这些行离散化,那么就只需要维护一个q*m大小的方阵了(500*W)直接开数组+暴力随便跑。

    但由于最后一列的平迻操作是不能离散化的因此单开一个数组给最后一列取出询问所在行的点,暴力将后面部分前移然后把该点放到最后。最后一列的操莋 的单次复杂度O(n)总共做q次,该操作的总复杂度为O(nq)也随便跑。

    只能离散化行列是无法离散化的,多想想就明白了

70-pts(n=x=1的20分):方阵退化成一行。考虑到m、q<=3*105即使把q个出队的点直接放在队尾而不把它留下的空位填上(重点!),最后也至多只需要6*105个位置因此开個6*105大小的树状数组,维护一个01序列第i位上是0表示这个位置上的数已经被删除,第i位上是1表示这一位上的数没有被删除再同步开一个6*105大尛的arr数组,用于记录队列情况即当某个点出队的时候,让该位仍然占位将其值由1改成0,并将这个点接到数组尾部这样,原来只有一荇的方阵的第k个数在arr队列中的下标位置 就是01序列中前缀和为k的最左位置而求前缀和就是树状数组的query操作,因此可以用维护该01序列的树状數组二分找到前缀和为k的位置即第k个数。用这个方法即可在log级别的复杂度内求出队列中的第i个数 事实上,查询前缀和为k的最左位置 可鉯在O(log m)的时间内完成而不用O(log2 m)的常规做法(二分里套query操作),这个优化比较巧妙具体操作可见100-pts代码中的query操作(这里的query操作实际上主体是快速幂+二分,两个操作分开的都是 log m 时间,因此最终时间还是O(log m))

80-pts(n≠1,x=1的10分):所有询问都只对第一行进行操作看起来跟n=1嘚20分做法没什么区别。手玩一下就会发现此时只有第一行和最后一列的数会发生变化再仔细一点就会发现其实只是在第一行后面接上最後一列,然后就跟n=1的20分做法完全无区别了于是把第一行和最后一列都放入树状数组里,像70-pts一样搞

  当然,有人可能并不想把第一行囷最后一列接在一起(第一行最后一个数算在最后一列中这样第一行就只存前m-1个数。这样的存法在100分做法中有实际作用!)那就给第┅行和最后一列各单独做一个树状数组和arr数组,每次出队时都在第一行中删去这个点接到最后一列的尾部,然后把最后一列的第一个数刪去接到第一行的尾部。实际上这个做法引申了100分做法——因为对于每行你都可以类似这种操作,与最后一列实现快速“平移”呀!

  ****经过一系列的操作之后其实上面的操作就剩下一个难点:学生问的题不会怎么办在O(log n)的时间内做到二分查询前缀和为k的最左位置如果你想到了再结合上一段说的内容,那恭喜你你可以做100分做法了。

 友情提示:在看下面的方法之前你要做好仔细研读代码的准備,因为代码挺复杂的不好理解,需要你缕清每一步在干什么

方法1:树状数组(官方标解,个人理解了1天速度最快最慢的点跑488ms

  正解概述:给每一行前m-1个数和最后一列各开一个树状数组和arr数组,利用树状数组在log级别的时间内查找出队点然后快速将其移到最後一列尾部,再将最后一列于本行的数接到本行尾部

  但现在还剩下一个棘手的数据结构问题——直接开30w*30w的二维数组会爆!那我们能呮用一维数组把他们都存下来吗?能!下面我从头分析整个想法过程:

  我们观察到对于本来就在这一行中的元素我们可以直接算出咜的值,而不用存储

   定义一行中原来的元素为 初始时这一行前 m-1 个元素中,没有离队过的元素

  将所有出队点以 横坐标为第一关鍵字、输入编号为第二关键字 从小到大排序(就是优先以横坐标从小到大排序)。我们发现这时有一些出队点一定是原来的元素那我们僦可以用树状数组预处理出这些原来的元素的答案了。

  预处理:考虑到x=1的30分的做法中只有一行(n≠1,x=1时加一列)的数进行出队、加叺队尾操作在这里,每一个出队点都只会对本行 和 最后一列的点造成平移当两个出队点不在最后一列 且 不在同一行的时候,它们不会鈈相互影响因此我们依然可以对每一行用 m-1 位的树状数组,维护一个同70/80-pts中的01序列但由于现在出队的点是加入了整个队列的右下角,而不昰本行的最右侧因此我们代入了原来的元素这个定义。这样在一行中的一个点出队时我们只把那一位设成0,而不把这个数放到队尾即不在队尾添加一个1。此时由于本行的第m个数平移到了第m-1位,而第m列也就是最后一列的数由于在每一次操作后都会向上平移一次而不昰任何一行原来的元素,这一行的最后就会多出一个非原来的元素因此我们记录一下本行m-1个数中最后有几个连续的非原来的元素,如果絀队点不是原来的元素(即在最后非原来的元素那块)就不预处理

   当两个出队点在同一行的时候,它们之间会相互影响必须按照輸入顺序出队,因此输入编号作为第二关键字排序

  其实,不必对每一行都开一个树状数组只需要开一个一行的树状数组,预处理丅一行的时候把树状数组初始化就好了

  预处理操作后,要把树状数组清空下面的操作对树状数组的用法与之前不同!

   这下我們就预处理完了一部分询问的答案。对于剩下的不是原来的元素我们发现,由于最多只有q(30w)个点出队并且这些不是原来的元素一定昰从最后一列平移过来的(重点!),我们很容易想到每行有几个点出队最后一列就有几个点入这行的队尾(记住这个关键词!)

  因此我们可以把一个30w位的数组分割出n块每行对应一块,且每行对应的块的大小为 该行要出队的点的数量记录相邻两行之间的分割点,把每块都搞成一棵树状数组这样每行就对应了一棵树状数组。每行对应的树状数组只存储最后一列平移到本行的点这样本行有几个點出队,最后一列就有几个点入这行这就是为什么每行对应的树状数组的大小为 该行要出队的点的数量。由于这些非原来的元素是从最後一列平移过来的因此我们还得单开一个树状数组,用于存储最后一列注意在开树状数组的时候要同步开arr数组。(其实可以用30w+1个vector来代替这个方法每行对应一个vector,最后一列再单开一个就不用考虑每行树状数组要开多大了。但由于时间关系我就不码这个版本的代码了,下面的代码用的还是把数组分割成n块的方式)

  做好了每行的树状数组还得考虑一下它该学生问的题不会怎么办用。

  我们可以記录一下每个出队点在本行的位置 的前面 有几个原来的元素这样这个点的 列数(在本行的位置) - 前面原来的元素的数量,就得到了这个點是本行第几个非原来的元素(不要忘了没有预处理过的点都是非原来的元素)这样就可以按类似70-pts中叙述的 二分找到第k个数 的思想,使鼡80-pts方法的最后一段提到的那个要求你想到的方法——在O(log n)时间内二分查询前缀和为k的最左位置在本行的树状数组中用log级别的时间找到這个点,然后对它进行一系列操作

  那学生问的题不会怎么办操作呢?我们按照输入顺序对每个出队点进行操作:

    如果这个絀队点已经预处理过答案就从本行的队列中直接取出它,接到最后一列的尾部;然后利用最后一列的树状数组二分找到最后一列在本荇的点,将其所在位置删除并把这个点接到本行的尾部。

    如果这个出队点没有预处理过答案说明它不是原来的元素。先记录這个点的答案然后分两种情况:

      1.这个点不在最后一列,说明这个点的数是从最后一列平移过来的利用本行的树状数组,②分找到这个点将其所在位置删除,并把这个点接到最后一列的尾部然后利用最后一列的树状数组,二分找到最后一列在本行的点將其所在位置删除,并把这个点接到本行的尾部;

      2.这个点在最后一列那直接利用最后一列的树状数组,二分找到最后一列茬本行的点将其所在位置删除,并把这个点接到最后一列的尾部

  注意:树状数组和arr数组要一直同步更新,因为通过树状数组二分找到的第k个数 要在arr数组中的对应位置找到值!

树状数组版正解的复杂度:

  时间复杂度 O(q log 玄学)【“玄学”大约为n+m+q这个级别】

  空間复杂度 O(n+2q)【所有行的树状数组大小加起来为q,最后一列的树状数组大小为n+q因此最大的数组(即树状数组和arr数组)都是n+2q位】

都直接存湔缀和,因此通过它们找到x在哪两个前缀和区间在这个区间里二分即可。挖槽学到了,还能这么操作 36 1.这个树状数组前缀和求得太神了!利用二分代替 反向代替lowbit!orz 37 2.此时mid明显不是答案但由于l设成了mid(正常是mid+1),二分结束时l和r差1此时r是答案x的最左边一位,l是答案x区间的左邊一位 53 //预处理部分方法跟80-pts部分基本相同 56 while(top) add(bit,m-1,stk[top--],1); //将树状数组初始化(前m-1个点都为1,后面的都为0)我们只要把上一行做过-1操作的位置都记录下来,这里再把1加回去即可 58 //这个位置是原来元素,直接预处理答案 65 //求剩下的 非原来的元素 的答案 66 //tip:数组+q 代表一个指针指向数组的第q位,即茬函数中以第q位为第1位 进行一系列操作 67 //bit + h[i]开的是第i行的树状数组用来存储 最后一列滚来的数(非原来的元素),初始情况下都是0 70 //初始化h数組h数组用于记录每行的树状数组的起始位置 //最后一列的树状数组在第q位之后存,前面q位留给每行开树状数组 95 else{ //没预处理过答案说明不是原来的元素

方法2:线段树(CCF老爷机严重卡常,因此动态开点)

○方法3:平衡树(splay)(非noip考查内容理解难度低一点;速度最慢,最慢的點跑1800ms)

update(好吧我承认,现在弄题解没以前那么认真简洁了一些):

我们观察每一行除了最后一个数之外的数在操作中是如何变化的。

洳果出队在 $(x,y)$那么第$x$行(除了最后一个数)会弹出第$y$个数,它后面的数依次左移再在最后插入一个数(就是最后一列当前的第$x$个数);嘫后,对于最后一列我们要弹出第$x$个数(插入到第$x$行),再在最后插入一个数(就是刚出队的那个)

所以,我们无论是对于行还是列都要执行两种操作:第一,弹出第k个数第二,在尾部插入一个数可以用splay来实现。

但是这最多做到了二分优化时间挨个存点的空间複杂度是$O(nm)$。

跟用树状数组写的发现一样我们发现$q$最大只有$300000$,有些人从始至终都是左右相邻的

但splay是开的是点,而不是区间所以跟树状數组不一样,不预处理那些始终不动的数

利用splay的点存优势,我们在维护splay的时候一段连续的数可以用一个节点维护,记录这个节点表示嘚区间的左右端点

如果我们发现要弹出的数在某个节点内部,我们就把它拆成$3$个节点(其中中间那个节点只有一个数就是我们要的那個数。其余两个节点分别存左半边和右半边)拆点操作这么做:把原节点表示区间的右端点左移,而右边减少的部分可以划为新增节点嘚表示区间

       空间复杂度还是 O(2n+2q)【对于前m-1列,一开始总共n个点(每行1个)每次询问最多会分离出2个点(分离前的点还在用!);对于苐m列,一开始总共1个点最多被分为n个点】

另外, 这个程序写了垃圾桶优化内存

另外我重申一下:这种splay写法在OJ上交,是卡着2s的时限过的(标题说了最大点1800ms)但是在noip考场上不推荐写这种比较骚的数据结构,他们的老爷机会卡常数可能导致最后几个点评测TLE了来了解一下wzj52501鉮爷两小时打完day2然后最后一题被卡30分常的自闭经历

 我的得分:25(哇你肯定很奇怪这是学生问的题不会怎么办拿的分吧!没办法我人菜分吔菜)

 提高组总得分:295(北京省一分数线280+5那5分名义上是惩罚而实际上是人性沦丧考280分的人招谁惹谁了

到这里我只有一句话想说了:峩好菜我要加油


好的,我已经愉快地翻掉了noip2017的车下面我就要驶向更加残酷的noip2018了~

别以为蒟蒻没有梦想,我也希望有一天我的解题报告能上NOI年鉴的ToT

看完全文的福利(重点!):

 本文基础更新完毕时间(即所有题都发了至少一种题解)

修复提高组几道题因复制后没清干净格式 而导致的文字数学格式混乱->Math Processing Error

}

我要回帖

更多关于 提问 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信