noip2018模拟测试赛里头的题目的口胡题解
是2019暑假做的。
这个暑假做的题非常少,一定要反思。
一:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1431
T1:略微改过的背包,先预处理一下头上放了东西的情况即可,假如头上放东西要判存不存在这种情况
T2:字符串暴力DP,最后再来一个DP统计答案
T3:裸的树剖或lct,树剖分类讨论一下三种情况
二:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1433
T1:分层DFS,判断当前不符合条件的段的段数,分类讨论怎么换
T2:先把柿子转成分段平方和最大,然后裸的单调队列搞斜率优化
T3:点数小,可以直接跑网络流;又因为网络流选择的路径的权值是从大到小排列的(spfa),所以每次流的都是权值最大的路径,啥时候总和小于0了就停下来统计
三:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1437
T1:考虑每个点头上的路径都至少要被经过两次,发现按照dfn序遍历刚好点的头上的路径都只被经过两次,所以这样就是最优解,那么只需要用set按照dfn序维护一下点权就好了
T2:边一定在最小生成树上的条件:(u,v)的权值小于u到v所有路径上的边的权值的最小值。那就可以把除自己-1等价为自己+1,然后跑最小割就行了
T3:每个点到根上的路径,和询问的点到根的重叠部分的总点数相当于lca的深度,那么每个点到根的路径上的点权都+1,最后统计询问点到根路径上的权值和即可
四:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1442
T1:用能够前缀和的哈希暴力判断(位权)
T2:不限制的答案是((1+2+...+n)^m),而每一个位置上不能选一个数a相当于这个项减掉a,最后统计+快速幂即可
T3:裸树剖
五:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1443
T1:每个位置二分判断即可
T2:按照题意,每行每列建个虚点直接连边,然后缩点跑拓扑dp
T3:分两类,上面的直接统计,下面的按照dfn序插入点,找深度符合dep[u]+1~dep[u]+k的点即可
六:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1447
T1:把边换成点,然后不向自己的反边连边,就可以做到限制了;除此之外就是裸的快速幂跑floyd
T2:二分给黑边加权,因为给黑边加权,白边被选的数量一定是不减的,所以具有单调性
T3:dp,线段树优化,每个位置按顺序插入询问就好
七:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1462
T1:比五的T2还裸,缩完点直接跑最长路即可
T2:LCT,或者离线树剖,提前判联通,记得最后不一定是棵完整的树
T3:至多一项互质就是两项以上不互质,那么建立34646(200以内质数个数)个中间节点,第一个46*46中的点(p,q)即为满足p|A而q|B,第二个即为p|B而q|c,第三个即为p|A而q|C,显然只要两边连起来的就可以匹配,跑dinic即可(虽然边数会看起来很大)
八:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1466
T1:随手推个柿子即可,注意p和q在另一种情况更优时应当转变为(1-p)和(1-q)
T2:跑AC机,上面有环而不能匹配到底就意味着有无限长的串了
T3:拆分成t[x]+t[y]-t[lca]-t[fa[lca]]来询问,直接权值线段树上查询即可
九:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1467
T1:因为DP做不了所以排序暴力贪心肯定是对的((( 其实是下面连上来的个数肯定至少是一个,而连上去最多就一个,所以优先连下面是对的
T2:二维前缀和一下然后整体二分即可
T3:淀粉质,然后发现树形DP不仅更优而且还好写(((
十:
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1468
T1:莫比乌斯反演模板
T2:严格次小生成树,每次找u到v路径上的最大值和次大值,因为(u,v)边没有被加入到最小生成树力,所以它的权值大于等于u到v路径上的最大值,那么判断一下是等于最大值还是大于最大值就好了
T3:考虑用堆维护五元组(x,y,l,r,v),代表右端点是y,左端点范围是l到r,x是l到r范围中的最优位置,而这个最优值是v,每次取出堆顶的最大值,然后分为两个新的区间(l,x-1)和(x+1,r),用可持久化线段树维护并查询这两个范围中的最大值v1和v2(最优位置为x1和x2),插入两个新的五元组:(x1,y,l,x-1,v1),(x2,y,x+1,r,v2),如此反复,取到第k个的时候就是第k大的了
十一
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1469
T1:暴力枚举错误的然后高斯消元验证,注意eps=1e-2
T2:先缩点,然后对于每个点拆点,然后设置点的权值是1,每次最大费用最大流,每找一次增广路相当于多开了一条路,那么ans+=1,这样就可以利用费用流的“可以反悔的贪心”的性质来模拟了
T3:是个SA 暂时不会
十二
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1470
T1:显然的状态压缩,每个状态记录能否走、要走多久即可
T2:树分治,因为k只有1e6,所以暴力维护就可以了
T3:显然这个东西满足单调性(模式变长了,出现次数肯定更少),那么可以用哈希暴力搞一搞套个二分
十三
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1471
T1:显然除了第二位以外全都能改成乘法,直接判一判即可
T2:是十一的T2的弱化弱化版...不仅没缩点还只用给边赋值就好了
T3:问题转化一下,给一个序列v,维护l~r的乘积,询问与这个乘积互质的数有几个,其中每一个v都可以表示成质数pi的正整数ki次幂的积,带修改
考虑与某个数互质的数的数量,
首先有(v_i=p_1^{k_1}p_2^{k_2}...p_n^{v_n}),因为互质的数量是积性函数,所以可以把答案转化为转化为(f(v_i)=(p_1-1) imes p_1^{k_1-1} imes ... imes (p_n-1) imes p_n^{v_n-1})
嗯,线段树先记录乘积,正好质数的数量非常少,所以记录一下哪个质数出现了,最后用乘积除以 每个出现的质数 再乘上 每个出现的质数-1 就是答案了
十四
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1472
T1:这种题出来给我们?脑子有坑吧
T2:容斥一下 考虑把所有范围内的2和9组成的数列出来 然后ans=一个数的倍数的个数-同时是两个数的倍数的个数+同时是三个数的倍数的个数-...+(-)同时是所有数的倍数的个数
然后从大到小来搜可以加快速度 因为越大的数的分支会少(越大的越容易超出范围)
T3:KDtree板子题,优先搜上限远的可以加快速度
十五
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1473
T1:经典的翻转其中一个序列的FFT
T2:博弈论给爷爬
T3:淀粉质,每层存两个线段树,一个代表距离自己为d的点加上的权值,一个代表自己管理的范围内距离上一层重心为d的点需要减掉的值,查询的时候前者减后者即可
十六
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1474
T1:哈希,先用kmp处理出s3在s1和s2中的位置,这些位置不能被子串包含,然后二分找最长的共同子串即可
判断是否包含位置:在每个s3的l和r处作标记,设当前串范围是slsr,若1sr的l的数量+sl~n的r的数量大于总数,就说明中间包含了s3
T2:简单期望DP f[i][a][b][c]代表第i次攻击后 剩a个血量1 b个血量2 c个血量3 的期望
注意不要管血量上限,这个题的数据是错的
T3:从高位到低位,用权值线段树找l~r中是否存在这一位符合要求的数就可以了。
因为当前区间总是存在符合之前的所有条件的数也即一定有数的,所以如果一个区间不存在符合条件的数的话,另一个区间肯定有不符合条件的数的,一定能找到解。
十七
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1475
T1:设dp[i][j][k]代表i号点(深度d),祖先们黑或白的状态j,共有k个黑色叶子节点的最小解,那么有 dp[i][j][k]=max(dp[i<<1][j或j+(1<<d)][k1]+dp[i<<1|1][j或j+(1<<d)][k2])(k1+k2=k)
T2:容斥,l和h先除以k,设dp[i]为[l,h]区间内任选n个整数,gcd为i的倍数方案数,显然dp[i]-(dp[2i]+dp[3i]+...+dp[上限])就是gcd为i的方案数了,从大到小更新,那么答案就是dp[1]了
T3:【由乃的OJ】起床困难综合征加强版 维护0...0和1...1分别从左、右进去出来的会是什么 然后尽量取1就可以了,注意z的上限
十八
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1476
没做。
十九
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1477
T1:考虑k个点最小,那么肯定可以把这k个点按顺序访问的结构看成一个主要的链+一堆旁逸斜出的枝条,这些枝条都要走两遍
那么考虑dp[i][j][0/1/2]代表必选第i个点,目前选了j个点,而第三维的0代表当前整个集合都是枝条,1代表当前选择的集合里有一个是其中一个端点,2代表当前选择的集合里已经有两个端点,那么有:
tmp[j+k+1][0]=min(tmp[j+k+1][0],dp[u][j][0]+dp[v][k][0]+2*w);//端点不在前面的子树里也不在当前子树里,那选择的这一组都是枝条,要走两遍
tmp[j+k+1][1]=min(tmp[j+k+1][1],dp[u][j][1]+dp[v][k][0]+2*w,dp[u][j][0]+dp[v][k][1]+w);//当端点在之前的子树里,那么当前子树连上来这一块就是枝条,否则若在当前子树里这条就是主要的链上的
tmp[j+k+1][2]=min(tmp[j+k+1][2],dp[u][j][0]+dp[v][k][2]+2w,dp[u][j][1]+dp[v][k][1]+w,dp[u][j][2]+dp[v][k][0]+2w);//以此类推
其中tmp是因为更新顺序比较麻烦所以新建立的数组。注意枚举的范围,必须做到严格(n^2)
T2:X数组的范围非常小,询问的范围也非常小,那么就可以暴力用可持久化01trie了,当前面的几位已经确定的时候,每次找当前这一位若填1会把排名加多少,小于k就走1,否则就走0
T3:结论题,一个点的距离最远的点一定是树的直径的两端(否则这个就不是最长的直径了),那么分奇偶讨论就行
二十
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1478
T1:研究一下规律,设S是原串,S=ABA,那么原串可以改为ABA ABA
然后扩展:ABAAB ABAAB,ABAABABA ABAABABA,ABAABABAABAAB ABAABABAABAAB...
研究一下半边:ABA ABAAB ABAABABA ABAABABAABAAB...
A的出现次数:2 3 5 8... B的出现次数:1 2 3 5...
就像个斐波那契(这个结论不会证啦啦啦
那么暴力统计就好了,求1~n中的出现次数时,每次都是由前面的串接上来的,所以可以分成多个斐波那契项的长度的串,那么每个斐波那契长度的串中的每个字母出现次数都统计一下,此题就解决了。
T2:我们定义一个子树x是必胜的,当且仅当存在一个儿子y,满足a[x]>a[y],且子树y必败,否则认为子树x必败。
对于必胜子树,就每次把小人移到那个a[x]>a[y]且必败的子树,如果它移回来,你就再移回去,最终其不能再移回来;对于必败子树,如果你选择了a[x]>a[y]且必胜的子树,你就把胜利交给了对方。
如果你选择了a[x]<a[y]的子树,后手可以移回来,最终总能阻止你往这个子树走。
那么DFS判断一下就行了
T3:分治FFT,首先减法的部分可以序列翻转+只统计正数,加法的部分先桶排,然后分治一下,每一个lr的段都是lmid和mid+1~r匹配
二十一
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1479
T1:前面的trick,最远的点就是直径上的点,然后单调队列维护最小值和最大值dp就好了
T2:考虑最后出来的序列,肯定能拆成两个递减的子序列(因为拿出来的时候就是两个递增的子序列,反过来就是递减的了)
那么我们设当前序列能拆成两个递减的子序列A和B,并钦定B的最小值b比A的最小值a大
设dp[i][j]代表当前序列长度是i,a=j的序列的种类数
那么考虑我们要插入第i个数x,当a<x的时候,x就应该在B序列中(否则A就不是递减序列了),此时两个序列最小值仍然是a,那么就有dp[i][a]+=dp[i-1][a]
当x<a的时候,x就应该在A序列中(否则A序列和B序列就不满足钦定的条件,会与另一种情况重复),那么就有dp[i][x]+=dp[i-1][a]
因为第k位后的数都是随便取的且最后一位不会对序列产生影响,所以最后的答案就是(dp[k][i] imes 2^{n-k-1})
注意可以一开始就消掉1的影响,就可以避免1在前面就被取了
T3:首先应该是二分最短的距离。判断考虑2-sat,每个点拆成0和1代表这个点是否应该取。那么xi和yi之间的连边就是 xi0-yi1 xi1-yi0 的双向边,然后冲突的就应该是每个的1连向冲突的0的单向边,然后跑tarjan,如果x和y的同一种属性在同一个联通块里,那么就意味着冲突。
二十二
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1480
T1:考虑每个节点u的儿子们v,设他们中黑的权值为b[v1vk],白的权值为w[v1vk]
显然每个子树都是独立的,所以白和黑可以任意切换,那么我们就应该使得每个子树选出来的和u的颜色相同的权值的和<=x[u](毕竟u可以任取),若>x[u]就无解了
那么考虑在<=x[u]的条件下,为了让父亲和祖先们更容易凑出来<=x[u]的值,我们就应该让另一种颜色的全值和尽量小(因为当前节点颜色的权值和是固定的x[u])
那就可以DP,和当前节点同颜色的权值和尽量大,另一种颜色就尽量小了
T2:显然最小割,然后每行每列创个虚点把边数缩小为(n^2)级别就行了
T3:NTT给爷爬
二十三
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1481
T1:我们可以发现,两个不互质的数的相对位置是固定的。对于alice的要求,把所有不互质的数的两个数连个边,然后我们要在每个联通分块里面决定一种顺序(也就是决定边的方向以组成DAG)使得字典序最小,那么我们决定顺序时只需要从小到大搜索,这样就可以让小的尽量呆在前面了。最后bob想要让它尽量大,那就用topo找字典序最小的就行了。
T2:首先应该是容斥,难点在于要算出有1个、2个、3个、...n个位置不符合条件的序列个数。考虑抽象出一个二分图,左边的n个点代表n个位置,右边的n个点代表n个权值,那么把左边的i和右边的i-k和i+k连上去。这时候我们可以发现这个二分图分成了多个链,任意的链都是由编号%k相同的点构成的,那么我们可以把每个链抽出来,满足这个链中的任意连续两条边不能同时选,而每选择一条边就相当于决定了某个点取某个值。那么就可以dp,先把边重新编号让一条链里的边都是连续的方便转移,dp[i][j][0/1]代表目前到了第i个点,选择了j条边(也就是说有j个位置的取值是不符合条件的),当前节点连接的上一条边是否要取,记录一下每个链的头在哪里,那么转移方程就显然了(注意链的头部不需要考虑上一条边是否取,压根就没有上一条边),m个位置不符合条件的序列总数就是dp[2n][m][0]+dp[2n][m][1]。
T3:考虑维护(lsum=a1 imes1+a2 imes2+...+an imes n,rsum=a1 imes n+a2 imes(n-1)+...+an imes 1),维护的时候可以自己推推式子,利用size即可,显然答案即为(exp=sum of all segments/((n+1) imes n/2)=(exp of l + exp of r + lsum of l imes size of r+1 + rsum of r imes size of l+1 + val imes size of l+1 imes size of r+1)),然后修改的时候(exp+=n imes (n+1) imes (n+2)/6 imes d)
二十四
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1482
T1:考虑初始有多少个红球,然后发现假如取球的过程中没有把红球取完过,那么一定可以在初始红球数量较少的情况被统计到,所以钦定必须要把红球取完就行了。
T2:要 polya 先咕掉
T3:SAM板子题,利用parent-tree先求出每个节点代表的字符串出现了几次,两种情况分别设置成出现一次或者出现正常次数,然后按照类似二分的方式找到k大即可
二十五
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1483
T1:考虑设dp[n][i][j]为目前枚举到第n位(第一种颜色肯定就在第n位),第二种颜色上次出现在第i位,第三种颜色上次出现在第j位的情况数,转移显然,然后针对每一个不同的条件把某几个状态设置为-1即可,注意每个条件的ri肯定就是枚举到第ri位,所以只需要枚举后两种颜色就可以完成预处理了。
T2:
T3:
二十六
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1484
T1:
T2:考虑整体二分+可以撤销的并查集,每次加入<=w的边,然后检查两个点是否相连以及两个点所处的并查集的siz总和是否>=z即可,注意要按照siz合并以维护并查集的深度在log以内
T3:
二十七
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1485
T1:考虑只要这棵树有一个完美匹配,那么显然Bob必胜,否则Alice必胜
T2:首先要判断能不能转得到;其次考虑当我们的序列长度等于5的时候我们可以通过一系列操作任意翻转间隔为1的两个柱子使他们同时上下颠倒而别的柱子不受影响;那么只需要分别考虑一下奇数位和偶数位要转多少次,也即对另一个奇偶性的位置上的颠倒的数量有怎么样的影响就可以了
T3:首先,若上下、左右均相通,那么无论多少阶都是一个联通块;若均不相通,那么个数也很容易数。否则我们先把原矩阵改成只有左右相通,然后每次我们的联通块个数=上一次棋盘大小-左右相通的格子的组数上一阶左右分别有几个可以接在一起的联通块即可(比如,第一阶到第二阶的时候,只有自己本身的这样一个联通块可以和左右相通;第二阶到第三阶的时候就会乘上左右边缘相通的格子的个数;再下一阶就会再乘一次)。那么显然可以用一个矩阵维护这个玩意儿。(主要靠意会...很难说清楚的亚子)
二十八
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1486
T1:按Li从小到大排列 然后尽量优先站左边 显然这个样子站在左边的个数最多 然后剩下来的只能插右边 尽量选ri较小的 也就是调整空间尽量大的 就可以了
T2:显然先把1的边连向自己,然后把图变成深度<=k的树就好了,从叶子节点开始搜,每深度为k的一段就接到根节点上
T3:考虑初始状态为0...X的沙漏,显然每次都会把左右两边中的一段给“推平”,然后这样的沙子数在0...X排列时要么是一横行,要么就是一个横行+一个递增序列+一个横行,记录每次翻转前的递增序列两端就好了
二十九
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1487
T1:首先显然每个人看到的颜色数不可能相差超过2;那么相差等于1的时候就数一下有多少个人看到的帽子数是较多的,那么他们带的帽子一定有同色,其他的就是没有同色的,算一下在不在范围内即可;相同的话考虑两种,一种是每个人带的帽子都有至少两顶,一种是都是只有1顶,分别判断即可。
T2:考虑把棋盘动变成洞动,设dp[u][d][l][r]为洞往上走u、往下走d、往左走l、往右走r的最大答案,那么发现每次想要把某一个加上1的时候,这个矩阵(ud,lr的矩阵)可以相应地扩展这一行/列,因为这样不会使消失的东西更多,按照上述转移就可以了。
T3:
三十
http://xsy.gdgzez.com.cn/JudgeOnline/contest.php?cid=1488
T1:首先肯定上下一起枚举,而且下边的只能从上边的前面的位置得到,那么开个双向队列,维护一下当前点要在哪里停下来,然后上面多一个新点就从头加入一个值,若下面缩了一位那就看看能不能把队尾的那个停止的给去掉,因为不需要停止了,直接和上一个点那个一起动就好了。最后数一数队列的最长长度即可。
T2:当(r-l+1)比d大的时候显然可以买得到。那么对于小的那些用树状数组区间加一下,直接数每个位置上碰到了几个就好了,因为是不会被两个位置同时碰到的,这样是调和级数乘上log的复杂度。
T3:考虑加上了这个值以后对上面的影响,分段树剖修改就好了。