乱七八糟的都先放这里了4

常见trick

当枚举与DP结合时,可以在枚举dfs过程,改变i之后,只更新i之后的DP数组,复杂度从 O ( p n n ) O(p^nn) O(pnn)变为 O ( ∑ i = 1 n p i ( n − i ) ) O(\sum_{i=1}^np^i(n-i)) O(i=1npi(ni)),估计一下会少个n。

一种每个东西状态只会改一次(特指从x变为同一数)的题,可以考虑暴力,常见手段为摊还分析和并查集。

考虑一类数列上建图的贪心问题中,图中环、链是否有编号连续的性质。

如果每次询问区间的某个值,又是离线的,建议想想分治。(loj6490)

线段树有多个值多个复杂操作难以讨论维护,考虑运用(max,+)等矩阵。(uoj164)

long double可以处理到1e300左右,但是精度只有十几位,有些可以有相对误差的题可以换高精度为这个。

撤销操作一类问题考虑撤销后回到什么状态(一些孤立不成联系部分可以去掉),要大胆猜想仔细论证。(nfls594(contest926T2))

bitset维护是否有重复元素时,考虑以1表示出现奇数次,0表示偶数次,然后异或后看看1个数是否与总个数相同。

重心就是满足子树大小 > = ⌈ n / 2 ⌉ >=\lceil n/2\rceil >=n/2的最深点,也即dfn序最大点。

对于两者之间有些元素相对应的题,考虑元素在哪里联系更紧密(限制条件简单严格),就在哪里DP计数。

体积和有上界,无价值背包,应当运用二进制分组。

对于每个值之间关键处只限于大小关系,而ans指向最后剩下的数这类问题,考虑二分,然后以分界点01染色后简化问题。(CF1322E)

对于 f [ l ] [ r ] f[l][r] f[l][r]表示l到t成一段时,可以用 g = f k g=f^k g=fk,其中 g [ l ] [ r ] g[l][r] g[l][r]表示l到r成k段。(lg8864 )

如果要求每个点逐一达成某一要求的最小代价,考虑这些点到达要求的顺序数列,然后相邻之间的转移等可以产生贡献,然后继续解决问题。(lg9021)

打monster等问题,先考虑两个小怪的顺序与合并,暴力讨论,再扩大到n个怪。(hdu6757 Hunting Monsters)

对于一堆不等关系,然后求方案数等问题,同时变量不多,考虑数位DP(可以倒着更好考虑,多记一个进几位)。(反重:求熵)

钦定几位来做容斥计数是好方法。

有一些最大化问题可以牵扯到图论模型,如每个元素只产生一次贡献,且是与另一个一起产生,那么就是最大生成树模型。(CF1305G)

当有若干维偏序条件下的DP时,可以以一维为转移顺序来去掉一维偏序限制。

全取完问题应当考虑min-max容斥。

注意讨论局部解,如n=1、k=1等情况下可能可以扩展回原问题。

莫比乌斯反演:

F ( x ) = ∑ x ∣ d f ( d ) F(x)=\sum_{x|d}f(d) F(x)=xdf(d)

f ( x ) = ∑ x ∣ d F ( d ) ∗ μ ( d x ) f(x)=\sum_{x|d}F(d)*\mu(\frac{d}{x}) f(x)=xdF(d)μ(xd)

注意dfn序的妙用(如求若干点LCA为dfn序最大最小的LCA,生成子树所含边数为dfn序每相邻两个的dis之和除2)。

网格图和树等特殊图的bfs求出关键点的kruskal重构树。(CF1307F)

可持久化边分树。

dij后建拓扑图跑拓扑DP。

一个流程在某一限定下方案数f(x)的平方在不同x的和,等价于两个流程,且两个流程都满足这一限定的方案数之和,这样子就去了一个平方。(管道取珠)

对于固定了一些值,要求给出未填值使若干相邻abs之和最小问题,一般是每种值构成一个连通块(不然劣),然后可以用最小割等方法解决。(CF1427G)

注意直径妙用(如求k条路径覆盖的最大权,一定是先取直径,然后变为若干个树继续贪(两个树内取两个过顶点的链或一个树内取直径))。

贡献提前/延后计算,比如一道贪心题,不知道该怎么取更优,或者确定的复杂度大,且不急于确定,那么可以打上标记,在后面需要计入贡献的时候可能可以方便处理(比如我get到了一个值,或者确定了一些值,所以原标记位可以更好确定或者用数据结构一次性处理标记)。(CF1693E)

如果x有一个下界限制,同时x+y为定值,那么可以改为y的上界限制(有时为了跑最大流)。

对于一个平面图,会有一些路径必然相交的性质,可用于找到一个路径的不等关系(航天飞机调度)

对于一类求出前k大的值的问题,以前k大区间为例,可以对于每个左端点求出一个最大值扔到堆中,每次取最大再扔个新的,要能快速求出每个端点的次最大等(超级钢琴)。

倍增妙用:k步之后每个点的值(一类置换问题等),前k步i位置的某个量之和(倍增),多次询问每个数去逐一替换另一个数(uoj812)。

大部分最大最小问题都可以尝试模拟费用流建图。

当线段树空间不对,分块时间常数不对的话,可以用线段树维护大块解决问题,灵活调整时间空间。(lg5897)

从路径相交(特别是平面图)发现四边形不等式然后再做也是常见的。(uoj672,lg5897)

有时候bitset可以做巨大多部分分(路径颜色翻转问题等)。

博弈类问题可以尝试向经典模型上靠。

可以大力把题目向一些经典问题上靠,然后疯狂转化(如靠到二分图最大匹配,然后二分图最大匹配=二分图最小点覆盖=点数-二分图最大独立集:nfls1312(contest850T1),nfls1311(contest850T3))

要求考虑[l,r]的东西,需要考虑莫队,线段树分治等(这些我不熟)。

对于删除问题(方案数,最大最小化),有一种方法就是标号从而把删除过程压平,从而变成标号相关的DP什么的。这里有一个问题,就是计数相关,特别是概率,我们需要考虑计数的时候需不需要把没有主动删除(可能伴随其他被删)的方案记进去。(nfls1290(contest852T1))

在进行DP的时候,如果有一维在转移的时候是需要O(n2)的(如卷积),那么可以考虑可不可以把这维折进去,具体就是变成xp乘到值里面(值一般是权值和),然后我们枚举x之后插值回去。(nfls1290(contest852T1))

有一类问题,是可以化为一个指针,然后指针两侧分别求值使二值的max最小之类的,可以考虑是否二侧都是单调的,然后二分两个取值函数出交点。这也告诉我们可以有时候可以暴力引入一个指针,然后用这类方法降低复杂度。(nfls1291(contest852T2))

对于一些问题,可以将其拆开,如括号对数等就可以分(),)(,)),((四类解决(nfls1292(contest852T3)),区间相交可以讨论二端点相对位置化简问题。(nfls1159(contest858T1))

一类问题可以引入变量理性分析,如区间加使每个数变为0,就可以引入每个区间的操作次数作为变量来列式分析,而不是乱撞。

考虑怎么压状态,如本来区间颜色抵消问题需要多记一个剩下的颜色,但是考虑只有可能是两侧的,所以可以记一个0/1即可,总结就是去除冗余状态。(hdu7277)

能否通过割一个点使得一些关键点两两不连通:一种方法是找出三个点的中心(将它们分开的割点),那么只有可能是这个,试下即可。一种方法是建出圆方树上虚树,如果是菊花且中心是圆点,那么可以。

高维偏序计算逆序对的时候,可以对每一维开n个bitset,然后对于每个数,我们把比他小的数的bitset(预处理每维前缀对应的bitset)拿来&一下然后count就好了。但是空间会爆,所以我们分块(长度B),然后每次一个块和剩下数计算,还有一个块内计算,这样的话每次bitset等数组只用开根号个长度根号的,且复杂度未变。

上一条的升级,就是变为带权max的DP问题的时候,可以类似的做,就是手写bitset,然后对于每一种sta预先算出对应的最大值。(具体可以看hdu7301)

一种背包,每个物品权值是[l,r]可以选若干,问最后可达权值有几种,如果l和r随机,可以证明用段维护可达位置,物品一一加入,段数是O(1)的。(hdu7309)

基数排序处理后,可以快速得到两个长度相同的后缀的大小关系。

取值函数是一条一次函数(其他可能也行)的一个f和另一个g(没要求)做(min,+)卷积,可以使用单调队列优化。

对于一类问题,需要区间加,区间查询为x的数的个数,这是没法解决的,但是有一些题目可以转化成查询最小/最大值个数就可以了。(CF526F)

∑ i = 1 c n t 1 ( c n t 1 i ) ∑ j = 0 m i n ( i , c n t 2 ) ( c n t 2 j ) = ∑ k = c n t 2 c n t 1 + c n t 2 ( c n t 1 + c n t 2 k ) \sum_{i=1}^{cnt1}\tbinom{cnt1}{i}\sum_{j=0}^{min(i,cnt2)}\tbinom{cnt2}{j}=\sum_{k=cnt2}^{cnt1+cnt2}\tbinom{cnt1+cnt2}{k} i=1cnt1(icnt1)j=0min(i,cnt2)(jcnt2)=k=cnt2cnt1+cnt2(kcnt1+cnt2)对于类似形式也是一样如果要求i<=j,那么不妨变成0<=j-i然后枚举j-i后一系列东西,改变枚举对象有奇效。(CF653G)

一个串如果有两个周期p,q,有强化版 Periodicity Lemma: p + q − g c d ( p , q ) ≤ n    ⟺    g c d ( p , q ) 也是 S 的周期 p+q-gcd(p,q)\leq n \iff gcd(p,q)也是S的周期 p+qgcd(p,q)ngcd(p,q)也是S的周期。(CF1205E)

如果是一类建造+生产的最优化问题,可以做图像,具体流程比较麻烦,建议看题。(nfls21664(contest864T1))

判断是否二分图的方法,最好的是抽离出一个边集使之变成二分图(树),然后看看这个的同色点间有无边。(CF1033E)

最好把问题转成常见模型思考。

对于加入和查询复杂度不同的题目,可以分块根号平衡,或者是多叉线段树。

对于一类题目,矩阵中,形如有一个固定点,然后另一个点在一个特定线上,需要查询矩阵和*某种和ij有关的值之和,然后有多次,可以使用高次差分来打tag一次性计算。(hdu7340)

对于一些问题,可能直接必胜必败比SG好做。

monge矩阵的k次(max/min,+)卷积的每个位置关于k凸。

对于一种单调队列+区间覆盖问题,可以用并查集处理区间覆盖。

对于去掉若干子树后的答案,又有若干子树是不可去的,可以处理前序和后序dfn上的dp,然后合并。(杂题3)

对于决策树比较大的题,尽量写dp,而不是尝试手玩一种策略。

对于多种转移时,也可以有“复杂度平衡思想”去设计dp。(CF1608F中f设种还是个)

ddp维护子树哈希。这里树哈希建议使用 f x = g ( d e p x ) ( 1 + ∏ f s o n ) f_x=g(depx)(1+\prod f_{son}) fx=g(depx)(1+fson)(g是随机映射)。(nfls12345(contest933T4))

一种权值是乘积的背包可以借用整除分块减小状态。(nfls12365(contest937T4))

字典树可以路径压缩从而使树高 O ( n ) O(\sqrt n) O(n )。(nfls28(contest938T4))

线段树二分!!!

对于一类除了子树外部分的题,如果问题需要线段树合并,那么一类方法是,线段树储存当前被删部分的信息,具体还有很多扩展,建议看题hdu7313。

一类问题是k次随机操作,然后求期望,可以用矩阵快速幂。(hdu7315)

多点问题可以转化成2点乘上组合数。(hdu7320)

对于一类”……外max/min“问题,考虑路径/子树是否含1/n。(hdu7333)

根号平衡!

对于一些题目必胜/必败比SG更好用。

启发式分裂。(hdu7347)

贪心思路:

首先尝试简化问题,处理一些特殊情况,尝试拓展。

然后尝试一些常见方法:借用排序固定顺序(用两个元素比较的局部法),简化状态(如取A之后一定取B,那么可以把A和B合为一个C),分类讨论(分几类分别排序),极端情况/手段(如除非游戏结束否则不取A这样的决策是否优),猜结论(如是否顺序与答案无关),考虑逆序过程(如打怪兽游戏)。对于博弈类问题,还有:转为经典博弈模型,SG打表。

最后确定了一些顺序关系之后,尝试DP或者数据结构来维护。

一种策略类问题,对于不同终态(如结束时间)有不同策略,要求最大化,那么还是可以用一个时间-价值函数来做。(nfls21664(contest864T1))

bitset可以记录每位由谁掌控来做一类问题。(nfls3061(contest867T1))

容斥原理来降低复杂度。(CF920E,CF1508C)

通过造两种方法然后分治来降低复杂度。(abc313f)

一种问题可以通过分讨x>B,x

注意打表之后,如果找不到规律,应当尝试手动构造,这样可能可以发现意想不到的规律。

∑ l o g p n = O ( n / l o g n ) \sum log_pn=O(n/log n) logpn=O(n/logn)

f函数和f[x]^1的函数的FWT,每个位置abs相等,可以从FWT卷积的过程来理解,由于 f [ x ] = [ x = = y ] f[x]=[x==y] f[x]=[x==y]的FWT是一个只有1和-1的东西。

如果wqs二分题目要求输出方案的话可以在斜率对应要求的时候,像平常的方法一样记一个转移过来的前驱,然后输出即可。

构造所有勾股数:x2=u2-v2,y=2uv,z=u2+v^2。

注意一些情况下常见方法会有反例,要thick twice所有反例细节后再写代码,如有边权是0,那么不能直接点分治找重心,要缩0边后点分治。

对于一些题目可以考虑逆过程。比如操作是加法以及和0取max,那么逆过程就是要保证始终>=0,相对来说从离散的取max(画出函数形式很怪,有很多折点)变成了纯粹的减法+始终>=0的限制条件。(CF505E)

对于一些需要写转移的题目,建议养成画自动机的习惯,一些性质(比如冗余计算)可以更好体现。(CF506E)

对于图的题目,一般都会有tarjan的影子(强连通分量的影子),多往这里想。

挖掘“中心”的性质,以这些点为根,或者作为特殊对象可以优化过程。“中心”指向外值会单调变化,或者其他可以保证“中心唯一”的特征。(CF516D)

要学会抽象命题,转述命题。(CF526G)

要对于欧拉回路问题更加敏感,多往这个思考。(CF527E,CF547D,CF723E)

二维坐标系整点构成的凸包点数上界是 O ( C 2 / 3 ) O(C^{2/3}) O(C2/3),C是值域。

对于一些问题,不要马上向树剖,线段树,KDT按,大部分在离线情况是可以有好写的低复杂度写法的,要充分think后再写。(CF555E)

凸函数(凸的方向一致)之和还是凸函数,在树上也适用。(CF566C)

对于相关性不大的两个二维操作(可以用KDT维护),那么可以考虑能否拍平成两个一维操作(线段树)。(CF571D)

三角形的操作。(CF575I)

对于一定条件下可走边/点才解封的题目,可以枚举一个个解封,然后分解封之前解封之后分别跑一次。(CF576D)

对于向一个集合内除了自己的点连边(2-SAT),使用前缀+后缀优化。(CF587D)

注意要搞清楚2-SAT的定义,2-SAT最好从原本定义出发(建两个点一个表示选一个表示不选),而不要乱触类旁通把连边乱搞。

注意可能在一些情况下可二分,其他情况特殊处理。(nfls1855(contest946T2))

多个长度相近的序列归并排序用类似线段树的结构两两合并可以保证复杂度。(nfls516(contest951T3))

对于状态数较少,可以直接对于每一个状态打出对应的答案,也可能询问离线下来询问,这个可以上dfs解决,然后dfs中可以有所谓“继承上一层”,所以可以优化复杂度。(nfls516(contest951T3))

对于形式奇怪的博弈题目,先上SG,不适用的话尝试手动模拟挖性质,然后还是不行就自己设计函数,具体来说要神似SG,也即“对于0状态,每个后继非0,对于非0状态,至少有一个后继为0”,具体来说也是要用mex,xor,+三种算符来设计的,例题可以带来启发。(nfls12367(contest709T1))

不同形式的hash的base和mod没有要求一致,那么可以通过刻意的不同来优化。(nfls12368(contest709T2))

当abs与最大化同时出现的时候,抽象理解就是一个类似取max操作和取max要求同时出现(也可能是min的),那么我们可以暴力把类似取max操作拆开,然后在后面最优化的过程中合回去,感觉说不清,强烈建议看例题。(CF1859E)

多往图论建模考虑。(CF468E)

“终态放入到始态”的DP思想,讲的清楚一点就是在始态的时候就计入终态的贡献,但是只有当当前的sta到达过目标后我们才把这个东西计入答案。(CF1810G)

可以尝试先用松命题处理然后紧回去,典型例子就是把模数改小。(hdu7363)

直接容斥计算和DP两种计数方法都要想,不要像哪个就死磕哪个。

如果有两种标号,可以尝试以另一种标号建树,然后撒原来用于建树的那一种。(hdu7385)

常见错误

线段树要四倍空间

当long long范围时,要写成1ll<

特殊值忘记统一(如上文为0-n下文写成1-n)

理解错题意之没有看从0开始标号等

为了测试subtask等更改代码后忘记改回来

subtask对应条件写错

使用memset导致TLE

及时保存

注意一些容器及时清空

对于一类for(){if()->计数;其他操作}这类写法,注意可能for外还要在if一次计数

在开vector,deque等stl的时候,不能开过多。

有时候函数不指名类型没有报错,甚至本地正常跑出答案,但提交大概率挂,所以最后要检查一遍是不是都写了类型,是不是都写对了(可能char类错写为int类并不会报错,跑出来也对)。

谨防诈骗题,NOIPT2未必简单,NOIT5未必难,不要一开始就框定在高级算法,甚至认为一定要转好几个弯才能解,经典例子就是UNR7的T1。

注意精度,尤其是开根号。(hdu7324)

注意题目信息,没有给的东西就不要按常理理解。(如没有说不重合,就是可以重合)

空间记得开够。

注意边界,可能有反例。

注意数组都要尽量多开一部分,比如字符串最后一位有一个\0,如果是多少位就开多少,会导致数组越界一系列问题。

注意在开高维数组的时候,最后一维尽量连续访问,否则cache miss会导致常数多十几倍。

cout<>a[i++]>>a[i]还有i=i++这些都是ub,所以尽量写得规范一点。

注意特判不要写挂。

注意不要莫名奇妙引入inf,iinf等来保证一些偏序关系,很可能出事故。(hdu7354)

=不要写成==

==不要写成=

注意审题!

在写三目运算符的时候三个地方一定都要加括号!

nm不要写反。

注意一些相对显然的细节问题,比如dp忘记写取min。

结论题多捏几组例子再找规律,更好的是直接打暴力。

审题细心冷静。

注意从源头上面审视做法有没有假。比如自以为画了一个凸包已经干出了所有的有效线段,只要一个指针来找所在段即可,最后调了半天发现其实引入了不少无效线段,所以移动指针会爆,CF1858D。

注意一些常见的结论换了场景很可能假。

注意对一些边角的特判。

注意审题,比如给出的是环还是链。

注意边角,比如如果想找n的最低位1,处理不好就会在n=0的时候出问题,特别是有一次写了一个for函数找,然后就没有return值,本地还是对的,所以最好都要有return值,对于这些wall的报错最好都处理掉。

对于一些没有自信同时难写的结论,在付诸实践前建议先想想其他的,同时先写一下暴力和其他题,如果写完之后发现大样例WA了,那么先改改细节,还是过不了那么大概率就是假了,这个时候要冷静弃坑。

常见对偶记录

1.最大流=最小割

2.二分图最小点覆盖=二分图最大匹配

3.最大独立集=总点数-最小点覆盖

4.最大权闭合子图=正点权和-构造最小割

5.最小路径覆盖=总点数−拆点二分图最大匹配

6.最长反链大小=总点数−最小链覆盖

7.原图最大团=补图最大独立集

经验与教训

比赛

在肉眼查错时,要本着自己哪里都有问题的心态查,不要有这里肯定对等想法,查若干次后可以部分忽略不查,不要被自己代码逻辑带进去。

写对拍的时候要充分顾及边角情况,如大数据,n=1,点数极密,点数极疏,最短路几长,链等即使感觉没有问题,如果有时间不妨构造出来测测。

不要删东西,进行代码可持久化。

在debug的时候,考虑重新读题理一遍思路,和重构,重构不要复制之前代码。

题目难度乱序!!!题目难度乱序!!!

一道题目如果调了30min+,而且没有可调hack数据没有头绪,那么建议先写其他题,或者写对拍。

当你需要一个拍的时候,无论有多难写,都要写,当你只能重构时,无论多烦,也要remake!

冷静审题,审三遍!冷静审题,审三遍!冷静审题,审三遍!冷静审题,审三遍!

题目简单但是多的比赛

首先签到一定要快,不要抄代码,否则很容易抄错等问题。

对于数据结构,要有所顾虑,如果比较巨大可以先放在一边,但是在后期没题写时必须毫不犹豫开写。

在最后冲刺的时候,特别要注意读题。

再说一遍,不要复制板子代码,特别不要复制别人的(根本看不懂然后疯狂改挂)。

double题和分讨题处理方式和数据结构一样。

everyday

在平时自律一点,不要怎么容易进入感性状态,这个状态浪费时间,同时没有提升,应该定期观察是否有这个问题立马解决。

少说话多做事。

专注一点。

在为人处世方面要伪装自己,用相对友好的形象。在网络上,基本不要发言,否则由于网络话语体系与生活话语体系的差异,对于网络萌新极大可能会丧失基本理性或者发出过于原始思维的声音。

在生活中要学会控制自己,控制自己的眼睛和手,来达到与世隔绝的效果。

未进入心流时不要听过于亢奋的歌,否则很可能进入大脑真空的感性状态。

把“我想”变成“我不应该”。

要辩证的思考,正反论证,不要有“不就应该……”的思维。

不要用过于纯净的心看,要努力让自己变“狠”,比如对于人渣态度一定要坚决。

一些零碎

题目:qoj集训队互测,ioi2021作业, h t t p s : / / t r e l l o . c o m / b / p D F l B K e g https://trello.com/b/pDFlBKeg https://trello.com/b/pDFlBKeg,还有以前做过的题目有一些非常妙,但是没有典型trick,可以重做。

随机unsigned long long范围的数是mt19937_64

uniform_int_distribution(l,r)(rnd)中的T可以替换为其他类型

return ……,int(n);可以使代码更美观

动态开bitset:

template<int len=1>
void tmp(int a,int b,......)
{
    if(len<n)
    {
        tmp<len*2>(a,b,......);
        return;
    }
    bitset<len> f;
}

rand生成比较大的随机数要(rand()<<16)+rand()。

一些常见东西的大小,stl指空stl的大小,对于stl的大小要格外注意:

char 1Byte

bool 1Byte

int 4Byte

long long 8Byte

vector 12Byte

queue 40Byte

deque 40Byte

set 24Byte

map 24Byte

uset 28Byte

umap 28Byte

stack 40Byte

priority_queue 16Byte

测算空间的方法(单位Byte):

1.
class Base{
    int...
    bool...
};
int main(){cout<<(int)sizeof(Base);}
2.
bool *op
int...
bool...
bool *ed
int main(){cout<<(int)&ed-(int)&st;}

-Wall和-Wextra开在编译选项里面,用’ '隔开

-Wl,–stack=1024000000开在连接器命令里,与其他也是用’ '隔开,一般来说开1024000000是合适的,太大可能死机,这样子可以跑3e7层的简单dfs。

EOF也是一种字符,所以可以一个一个字符读,然后发现=EOF的时候return 0。

__int128通过/1e8分成两块输出。

在比较ab>c的时候用a>c/b会更好。

卡常技巧:

  • 减少取模
  • 卡循环上界
  • 适当储存减小cachemiss
  • 一些无效点不转移(如矩乘里面为0的不转移)
  • 一些取模改成加减
  • 只预处理有用的点,一些永远访问不到的信息就不预处理了
  • 快读

对偶原理学习笔记

主要就是视频部分,这里在补一下视频里面可能没说清楚的东西。

其实就是感性证明那一块,最后为什么>=c,我好像讲成了y之和>=c,这是不对的,既然是每条式子乘y之和,那么x前面肯定是带系数y的,所以是ay之和>=c。

感性证明这一块也可以听一下T1原题解,就是nfls contest 867 T2 3065花的视频题解,ducati以花为例讲了感性证明,比较清晰。

其他的除了讲的漏洞百出,模糊不清,语速巨慢(由于自己也不是很会)以外应该没有问题。

博弈论学习笔记

经典博弈模型

这里给出名字,内容,结论,但不证,证明自行搜索。

1.巴什博弈

有一堆总数为n的物品,2名玩家轮流从中拿取物品。每次至少拿1件,至多拿m件,不能不拿,最终将物品拿完者获胜。

就是如果%m=0的话先手输,否则后手输。

2.威佐夫博弈

有两堆各若干个物品,两个人轮流从某一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式: a k = ⌊ k ( 1 + √ 5 ) / 2 ⌋ , b k = a k + k a_k =\lfloor k(1+√5)/2\rfloor,b_k=a_k+k ak=k(1+√5)/2,bk=ak+k

3.尼姆博弈

2名玩家轮流从数堆物品中拿取一定数量的物品,每次拿取时先选择某一堆,再从中拿取任意数量个物品,至少拿1个,至多将这一堆物品全部拿走,不能不拿。拿到最后一个物品的玩家获胜。

如果 n 1   x o r   n 2   x o r   n 3   x o r ⋯ n_1\ xor\ n_2\ xor\ n_3\ xor\cdots n1 xor n2 xor n3 xor为0则先手输,否则后手输。

SG函数和各类模型

一个状态的SG值为后继状态的mex,两个独立游戏共同SG值为其xor。SG为正则先手胜,否则后手胜。

Anti-SG

SG计算过程全部一样,最后得出结论部分不同。

SJ定理(也就是当轮到某个人操作完决策集合为空时为输):

对于Anti-SG游戏,如果我们规定当局面中所有单一游戏的SG值为0时,游戏结束,则先手必胜当且仅当

  • 游戏的SG函数不为0且游戏中某个单一游戏的SG函数值大于1

  • 游戏的SG函数为0且没有某个单一游戏的SG函数大于1

Multi-SG

一个点的后继状态的SG,为这个后继状态含的各子游戏SG之和。

Every-SG

除了SG函数,再记一个step函数,有(v为当前,u为v的后继状态)
KaTeX parse error: Unknown column alignment: * at position 33: … \begin{array}{*̲*lr**} 0 & v为终止…

相对升级的经典模型

翻硬币游戏

一般的翻硬币游戏的规则是这样的:

N 枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按 1 到 N 编号。

游戏者根据某些约束翻硬币(如:每次只能翻一或两枚,或者每次只能翻连续的几枚),但他所翻动的硬币中,最右边的必须是从正面翻到反面。

谁不能翻谁输。

结论:局面的SG是局面中每个正面朝上的棋子单一存在,剩下的都换为反面硬币的所有情况SGxor和。

树删边游戏

直接进入图的情况。存在一个特殊点为根,每次每个人删一条边,与根不连通部分直接去掉,不能操作者输。

先是链,考虑链等价于一个边构成nim游戏。

然后是树,从这里开始不证。结论是两条链在一个点合并相当于SGxor,然后会伸出一条相当于SG+1。

最后是图,我们可以把所有偶环缩为一个点,把所有奇环缩为一个点伸出一条边,然后跑树的情况即可。

一些例题

1.staircase nim

游戏开始时有许多硬币任意分布在楼梯上,共n阶楼梯从地面由下向上编号为0到n。游戏者在每次操作时可以将楼梯j(1<=j<=n)上的任意多但至少一个硬币移动到楼梯j-1上。游戏者轮流操作,将最后一枚硬币移至地上的人获胜。

我们可以将奇数位看作一些nim堆,然后每次操作必然会改变这些nim堆的xor和,所以用类似nim游戏的结论即可。

2.POI2003/2004 stage I Game

我们考虑把每个有棋子的位置的左侧以及最右的划线视为一个一个分界点,分界点间格子数视为硬币数,然后就变成staircase nim游戏了。

随机化学习笔记1

模拟退火:

首先明确引进哪些变量

i n i T ini_T iniT 表示初始温度

e n d T end_T endT 表示结束温度

d d d 表示降温步长

s t a t e state state 表示当前状态

s c o r e score score 表示当前状态价值

c a l c calc calc 是计算state的价值的函数

for(double i=iniT;i>=endT;i*=d)
{
	state->nstate;通过一个微小改变变为nstate(如交换翻转等)
	delta=calc(nstate)-score;
	若询问求max.if(exp(delta/T)>=rand(0,1)) state=nstate;
	若询问求min.if(exp(-delta/T)>=rand(0,1)) state=nstate;
}

以若询问求max为例。

对于exp(delta/T),是一个学术界认为的比较好的量。

现阶段只需知道:

若nstate更优,则必更新,如果不是更优也有可能转移,exp(delta/T)满足要求,当delta>=0即更大,那if必为真,转移,否则凭后继状态优秀程度一定概率转移。

然后,模拟退火其实是刚开始分子处于不确定状态,疯狂游走,之后降温后,分子相对稳定,慢慢游走到最优值,故/T是优秀的。

算法注意点

这里 i n i T ini_T iniT有几种取法,一种是自己调参测试,找到较优秀的,一种是取最大可能ans,一种是随机100种状态,取结果的方差,一般用第一种就够了。

e n d T end_T endT则取 i n i T ini_T iniT的倒数或者自己定值。

d d d的话自己调参。

一个是calc可能可以根据state快速计算,而不是对于nstate整个重新算一遍。

模拟退火要求价值函数根据自变量尽量连续,否则就会掉到一个“坑”里,难以游走出来。

可以做多次模拟退火防止出生点在“坑”里。

根据退火定义,温度越低越稳定,故调整的长度参量与T有关会更优。

洛瓦兹局部引理:

这是学概率最理性狂欢的地方。

先介绍概念:

超图:即每条边连了多个点,每条边都是一个点集。

匀齐超图:每条边所连的点数相同。

如平时常见的图就是2匀齐超图。

然后有:

P r ( A ) Pr(A) Pr(A) 表示A事件发生概率

事件有p概率为坏事件,1-p概率为好事件。

若事件间两两独立,如果每件事发生概率都<1,则都不发生概率>0。

接下来介绍匀齐超图染色,每个点染1-q。

坏事件定义为一条边中的点颜色都相同。

边不相交意味着坏事件两两独立。

洛瓦兹局部引理讲的就是这类问题,是否有一种情况没有坏事件发生。

其要求是:

1.事件之间相对独立。

2.坏事件发生概率不大

这种情况下则有一种情况没有坏事件发生。

接下来定量分析:

定义超图(V,E),最大点度为d,边的大小为k,颜色有q种,自然对数为e。

则一条边坏事件概率为 q 1 − k q^{1-k} q1k

对于任意边,和它相关的坏事件数最多为kd-1。

那么有 e ∗ q 1 − k ∗ k ∗ d ≤ 1 ⟹ e*q^{1-k}*k*d\leq1\Longrightarrow eq1kkd1有一种情况没有坏事件发生。

玄学?玄学!

接下来是头脑风暴的证明。

将每个边变成点,若两个边有交,就用边连接它们对应的点,类似线图操作。

p为坏事件发生概率,为 q 1 − k q^{1-k} q1k,D为一个点的最大度,为 k d − 1 kd-1 kd1

先转化一步,原式等价于 e p ( D + 1 ) ≤ 1 ⟹ P r [ 无坏事发生 ] > 0 ep(D+1)\leq1\Longrightarrow Pr[无坏事发生]>0 ep(D+1)1Pr[无坏事发生]>0

再加一些概念:

B \mathcal{B} B表示坏事件集合, E E E表示边集,注意这里都是线图定义下的, B i B_i Bi表示坏事件发生概率, B i ‾ \overline{B_i} Bi表示坏事件不发生概率。

证明一阶段:

接下来要构造一组 x i x_i xi使得:
P r [ B j ] ≤ x j ∏ ( j , k ) ∈ E ( 1 − x k ) Pr[B_j] \leq x_j\prod_{(j,k)\in E}(1-x_k) Pr[Bj]xj(j,k)E(1xk)
x i = 1 D + 1 x_i=\frac{1}{D+1} xi=D+11

显然有 P r [ B j ] ≤ p Pr[B_j] \leq p Pr[Bj]p,这里 p = q 1 − k p=q^{1-k} p=q1k

那么我们要证的就化为 p ≤ x j ∏ ( j , k ) ∈ E ( 1 − x k ) p \leq x_j\prod_{(j,k)\in E}(1-x_k) pxj(j,k)E(1xk)

首先我们有了 e p ( D + 1 ) ≤ 1 ep(D+1) \leq 1 ep(D+1)1

那么原命题
   ⟺    p ≤ 1 D + 1 ∗ ( 1 − 1 D + 1 ) D \iff p \leq \frac{1}{D+1}*(1-\frac{1}{D+1})^D pD+11(1D+11)D

   ⟺    1 e ( D + 1 ) ≤ 1 D + 1 ∗ ( 1 − 1 D + 1 ) D \iff \frac{1}{e(D+1)} \leq \frac{1}{D+1}*(1-\frac{1}{D+1})^D e(D+1)1D+11(1D+11)D

   ⟺    1 e ≤ ( 1 − 1 D + 1 ) D \iff \frac{1}{e} \leq (1-\frac{1}{D+1})^D e1(1D+11)D

又有恒等式:
e x ≥ 1 + x e^x \geq 1+x ex1+x

   ⟺    e ≥ ( 1 + x ) 1 x \iff e \geq (1+x)^{\frac{1}{x}} e(1+x)x1

   ⟺    1 e ≤ ( 1 + x ) − 1 x \iff \frac{1}{e} \leq (1+x)^{-\frac{1}{x}} e1(1+x)x1

带入 x = − 1 D + 1 x=-\frac{1}{D+1} x=D+11

等式转化为
1 e ≤ ( 1 − 1 D + 1 ) D + 1 ≤ ( 1 − 1 D + 1 ) D \frac{1}{e} \leq (1-\frac{1}{D+1})^{D+1} \leq (1-\frac{1}{D+1})^D e1(1D+11)D+1(1D+11)D

证明二阶段:

接下来要证:
P r [ ⋂ 1 ≤ i ≤ m B i ‾ ] ≥ ∏ i = 1 m ( 1 − x i ) ≥ 0 Pr[\bigcap\limits_{1 \leq i \leq m}\overline{B_i}] \geq \prod_{i=1}^{m}(1-x_i) \geq 0 Pr[1imBi]i=1m(1xi)0
再引入一个引理:

S i = ⋂ 1 ≤ j ≤ i − 1 B j ‾ S_i=\bigcap\limits_{1 \leq j \leq i-1}\overline{B_j} Si=1ji1Bj

那么有 P r [ B i ∣ S i ] ≤ x i Pr[B_i|S_i] \leq x_i Pr[BiSi]xi

也即 S i S_i Si种的坏事件都没发生的情况时, B i B_i Bi发生的概率也不大。

证明在下文,此处先略。

首先有概率公式
P r [ ⋂ 1 ≤ i ≤ m B i ‾ ] = P r [ B 1 ‾ ] ∗ P r [ B 2 ‾ ∣ B 1 ‾ ] ∗ P r [ B 3 ‾ ∣ B 1 ‾ ⋂ B 2 ‾ ] ∗ ⋯ Pr[\bigcap\limits_{1 \leq i \leq m}\overline{B_i}]=Pr[\overline{B_1}]*Pr[\overline{B_2}|\overline{B_1}]*Pr[\overline{B_3}|\overline{B_1}\bigcap\overline{B_2}]*\cdots Pr[1imBi]=Pr[B1]Pr[B2B1]Pr[B3B1B2]
其次由 P r [ B i ∣ S i ] ≤ x i Pr[B_i|S_i] \leq x_i Pr[BiSi]xi可知 P r [ B i ‾ ∣ S i ] ≥ 1 − x i Pr[\overline{B_i}|S_i] \geq 1-x_i Pr[BiSi]1xi


P r [ ⋂ 1 ≤ i ≤ m B i ‾ ] = P r [ B 1 ‾ ] ∗ P r [ B 2 ‾ ∣ B 1 ‾ ] ∗ P r [ B 3 ‾ ∣ B 1 ‾ ⋂ B 2 ‾ ] ∗ ⋯ ≥ ( 1 − x 1 ) ∗ ( 1 − x 2 ) ∗ ( 1 − x 3 ) ∗ ⋯ = ∏ i = 1 m ( 1 − x i ) ≥ 0 Pr[\bigcap\limits_{1 \leq i \leq m}\overline{B_i}] \\=Pr[\overline{B_1}]*Pr[\overline{B_2}|\overline{B_1}]*Pr[\overline{B_3}|\overline{B_1}\bigcap\overline{B_2}]*\cdots \\\geq(1-x_1)*(1-x_2)*(1-x_3)*\cdots \\=\prod_{i=1}^{m}(1-x_i) \geq 0 Pr[1imBi]=Pr[B1]Pr[B2B1]Pr[B3B1B2](1x1)(1x2)(1x3)=i=1m(1xi)0
接下来证明引理:

考虑归纳,对于 j ≤ i − 1 j \leq i-1 ji1都已成立。

S i S_i Si中包含两部分一个是与 B i B_i Bi相独立的部分,不影响LHS的值,略去,另一部分记为 S i ′ S_i^{'} Si

有公式:
P r [ x ∣ y ] = P r [ x ⋂ y ] / P r [ y ] Pr[x|y]=Pr[x \bigcap y]/Pr[y] Pr[xy]=Pr[xy]/Pr[y]

P r [ B i ∣ S i ′ ] = P r [ B i ⋂ S i ′ ] / P r [ S i ′ ] Pr[B_i|S_i^{'}]=Pr[B_i \bigcap S_i^{'}]/Pr[S_i^{'}] Pr[BiSi]=Pr[BiSi]/Pr[Si]
又显然
P r [ B i ⋂ S i ′ ] ≤ P r [ B i ] ≤ x i ∏ ( i , j ) ∈ E ( 1 − x j ) Pr[B_i \bigcap S_i^{'}] \leq Pr[B_i] \leq x_i\prod_{(i,j)\in E}(1-x_j) Pr[BiSi]Pr[Bi]xi(i,j)E(1xj)
又有对于一个k,其中 ( i , k ) ∈ E (i,k)\in E (i,k)E ,有
P r [ B k ∣ S k ′ ] ≤ P r [ B k ∣ S k ] Pr[B_k|S_k^{'}] \leq Pr[B_k|S_k] Pr[BkSk]Pr[BkSk]

P r [ S i ′ ] = P r [ ⋂ ( i , j ) ∈ E B i ] = P r [ B j 1 ] ∗ P r [ B j 2 ∣ B j 1 ] ∗ P r [ B j 3 ∣ B j 1 ⋂ B j 2 ] ∗ ⋯ ≥ ∏ ( i , j ) ∈ E P r [ B j 1 ∣ S j 1 ] = ∏ ( i , j ) ∈ E ( 1 − x j ) Pr[S_i^{'}]=Pr[\bigcap\limits_{(i,j) \in E}B_i] \\=Pr[B_{j_1}]*Pr[B_{j_2}|B_{j_1}]*Pr[B_{j_3}|B_{j_1} \bigcap B_{j_2}]*\cdots \\\geq \prod_{(i,j) \in E} Pr[B_{j_1}|S_{j_1}] \\=\prod_{(i,j) \in E}(1-x_j) Pr[Si]=Pr[(i,j)EBi]=Pr[Bj1]Pr[Bj2Bj1]Pr[Bj3Bj1Bj2](i,j)EPr[Bj1Sj1]=(i,j)E(1xj)

P r [ B i ∣ S i ′ ] ≤ x i Pr[B_i|S_i^{'}] \leq x_i Pr[BiSi]xi
引理得证。

至此,洛瓦兹局部引理证毕。

接下来讨论一下其运用。

对于30-SAT问题,考虑输入量,d最大为1e5,故D最大约3e6,显然有 e p ( D + 1 ) ≤ 1 ep(D+1)\leq1 ep(D+1)1,故有存在合法解。

然后就是超级升级,可以构造一组方案,爆切NP。

先每个随机一个颜色,每个团检查是否合法,然后随机一个合法解。

检查O(n)次必结束。

证明超出暂时知识范围。

随机化学习笔记2

主要是几篇论文以及nflscontest877的专题中找的题,有些给出正解,顺序是按照我学的顺序,所以是乱的。

nflscontest877

A

随机化的话就考虑每次从区间中随便那拿一个过来验证,错误概率是4/5,所以大概100次就好了,但是会TLE。

考虑在随机化题目,可能有多次询问,但不带修这一类,我们完全可以在随机之后,采取聪明的离线算法。(这是很重要的思想,离线才是王道!!!)我们继续观察,发现这里我们询问多,序列短,为了达到平衡的效果,当然会想到根号数据结构(这种直觉很重要),所以我们在随机之后,考虑使用莫队一次性处理所有询问,就达到了询问O(1)处理的效果。一共 O ( n n + 100 q ) O(n\sqrt n+100q) O(nn +100q)

B

hint:建树。(我做这题只飞了这个)

我们考虑一下建树有什么用,建树建出来之后,可以直接二分图染色,然后直接询问黑点一次,白点一次就好了。感觉这个思想比较的朴素,但是还是需要非凡直觉,流程:是否二分图->二分图染色&可以一次询问一个点集->构建一个二分图后O(1)询问->寻找常见二分图->建树。

考虑怎么建树,这里其实挺困难的。

我们现在随便拿一个连通块x,尝试一较小次数接到另一个上,这里我们先算出每个连通块的大小,在建树过程中,这部分所需询问次数是O(n)的,然后我们把一个连通块视为一个点考虑。我们把其他的点(注意不是连通块)平均的分为两堆,用一堆y加上x询问,再询问y,那么就知道x和y中有没有边,如果有,那么就把另一堆扔了,继续递归成子问题,否则就把y扔了,递归成子问题。最后O(logn)次这样操作后,就锁定成了x和一个点间之间有边。考虑继续锁定,我们就变成了x这块平均分,然后点对块询问,也是O(logn)次。然后发现精细计算是4nlogn的,然后就爆了。

考虑优化过程(其实就是写题解写到一半发现假了,开始补救)。我们考虑优化第二个O(nlogn),因为这个看起来就很能从2nlogn变成nlogn。我们考虑每次取最小的一个连通块,让它里面的每一个点,和剩下部分做一个大的询问,然后就知道哪个点和外面有连边了,最后就可以省掉第二个流程,而这里由于每次取的是最小的,所以有一个类似启发式合并的东西,精细分析一下就是nlogn。

写到这里我突然发现可以继续优化。那么就是如果一个点和外界没有连边,那么在之后合并的过程中也必然没有连边了,这就很好,也就意味着我们实际上套用这个优化,也就是一次询问失败的点就不在询问,那么我们上面那个启发式的东西就可以改成每次随便选一个连通块进行,同时询问次数降为O(n)。

最终,一共2nlogn+kn。应该很优了,在题解区转了一圈,好像次数都比我高(大部分是4nlogn卡过去)。

C

深深感觉自己脑子不行了/kk。

就是每次随机选一个,然后把它的约数们每一个拿来试试,然后我发现自己怎么都不会算每个的cnt,于是就飞了。

所以就是求出gcd(x,ai),然后只在这里cnt加一,最后做一个狄利克雷卷积就好了(话说这玩意怎么做我都忘了),然后惊醒发现不可以狄利克雷卷积(话说写题解这么随意真的好吗)。我们求出x的所有质因子b,然后用这些来狄利克雷卷积就好了。

D

具体见2021国家集训队论文T2。

E

一个月后发现自己假了,没有考虑“你不知道每条信息具体是哪个点的”,正确解法写在“IOI2020国家集训队作业”里面。

自己想了一个,不知道对不对。

我们考虑如果枚举了i和j,i是叶子,j是i的父亲,那么我们知道,i剩下的元素一定与j相连,假设有一个k,那么我们知道j和k的交集必然与k相连,这样递归下去,我们就可以构建出一个树,如果计算过程中出现了矛盾,那么我们就换两个i和j就行了,这样子是O(n^3)的。

我们考虑优化这个过程,我们发现有一个必要条件,就是j的集合一定包含i的集合,并且除了树的直径为2的菊花情况外,i的集合不等于j的集合。我们特判完菊花,然后用bitset判一下上述的东西,就可以找到若干数对,我们在这些里面随机,那么随到的概率就很高了,我构造出来的最坏情况(可能我构造技术比较垃圾),随机次数也是O(1)的,反正感性一下随机次数总不会超过O(n)吧,反正这个时间挺松的。

F

我们使用类似A的随机,但是我们发现莫队的离线方法就失效了。

考虑回线段树,我们对于每个颜色开一个动态开点线段树,然后就可以快速计算次数了。由于有容错,这里我们只用随机100次然后取最大的几个就行了。考虑修改,我们使用一个ODT来支持,这部分比较简单,就是ODT上加区间删区间的时候顺便在线段树上区间加即可。

好像有人这样子过了,但是我感觉我来写必定TLE。

2021国家集训队论文 《一类调整算法在信息学竞赛中的应用》

调整解决匹配问题的基本思路就是对于每次随便选一个未用的点,我们在它的邻域中,如果有未用的点,那么直接配,否则以一定概率断掉它邻域里某个点的匹配边,然后它与那个配。

T1

一般图最大匹配问题。

我们运用相关思路,就是先随便找一个点x,然后看看有没有邻域未配点,有就连,否则以100%的概率让对方段,就是在邻域里面选u,u和原本配点v断边,然后连x和u。这样子在随机情况表现优秀。

T2

CF1168E

这个就是一个隐式匹配问题。

首先判掉无解情况,就是 ⊕ x i ! = 0 \oplus x_i!=0 xi!=0,同时可以证明这个为0就是有解的,由于这个和随机关系不大,是个sb构造,这里略去不写。

我们考虑一个排列一一与x序列匹配,然后xor要是一个排列。接下来就是同理了,也即每次从排列里面选一个未用的,然后看看有没有不会起冲突的x,没有的话就随便选一个,然后把会产生冲突的那一对断了。这个方法在表现上与O(n^2)相当。

T3

JOI2020 制作团子

这题阐明了调整法的“底线”,我们一定要先化成匹配问题,比如这道题里面,我们不可以直接看一串为整体乱做,这样子会引起不好分析,情况多,甚至导致正确率下降。我们要将理性,所以要先找一个为代表元,然后就变成了一个丸子和签匹配,这里考虑对称性,我们发现以中心为代表元也即白色是比较优秀的,这样子一圈一共涉及四种穿法,每个丸子都分布在它旁边,这样子就比较美观,同时整齐。考虑随便选一个未匹配的,如果有一个可以直接穿,那么就穿,否则就把矛盾的去了。这里就有了所谓“底线”,就是说调整法要求答案只升不降,也就是说如果有两个串与之矛盾,那么就不能删,这样会导致答案变小,如果这样子删了的话,就是模拟退火了,而模拟退火又是以一定概率接受,也就是说如果较高概率接受使得答案变小的大概率会导致最终答案的错误。所以我们就看看有没有只起一个矛盾的,然后以50%概率接受。这个概率是要当场调的。

T4

uoj544

比较经典的调整法。每次我们随机选一条边,如果成环了就一定不要,这个原因最后解释。如果没有成环,尝试加入这条边到边集,如果每个点的度数满足条件,就直接加入,否则以50%概率断掉起冲突的一条,然后加入。这里只有一条起冲突是因为相当于一条链,支出来了一条,那么显然断一条边即可。判断成环用LCT。

然后解释一下为什么一定不要,如果要了没有好处,因为我完全可以用几次第二种来解决了,要了的话并没有去优化这个过程,可以说一点用都没有。如果要了之后我们断的是一个相邻边,那么这样相当于在环上转了一格,一格诶,一般来说我期望需要的一定是十几个,甚至O(n)格,这一格屁都没用。如果要了之后我们在环上随机断边,那么假设有效的断点,也就是断了可以在之后使得答案变优的点数大概是O(1)的,所以基本选不到正确的位置断,反而多付出O(logn)的复杂度。

T4变体

一种是固定起始点,那么我们建s向起点连边,终点向t连边即可。

一种是哈密顿环,论文给出的是枚举一条边,然后化为上一种。但是我感觉这样子很慢,不如继续T4的过程,也就是判定结束条件改一下,当已经变成哈密顿路的时候,如果成的环符合要求,那么就接受并结束过程,不知道这样子的效率是怎样的。

一些可能优化

这里可能有一些调整改过来之后很快改回去了,所以考虑进行一系列调整,就是如果起了冲突,那么就改,改完后在其附近找,继续调整,这样子就一次性调整了一个局部,可能比较有效。

这里很容易卡到死角,所以可以改成模拟退火。

2014国家集训队论文 《随机化算法在信息学竞赛中的应用》

常见的随机化算法分为三类,数值概率算法,Monte Carlo算法,Las Vegas算法,具体不在这里赘述。

T1

CodeChef MSTONE

我们考虑先使用容斥定理,首先包含最多点的线段包含点的数量一定是 ≥ ⌈ n 7 ⌉ \geq \lceil \frac{n}{7} \rceil 7n的,所以我们考虑随机选点,那么一定有1/7的概率选中这条线,那么我们随机选两个点,就是1/49的概率选对,那么我们就每次随机选两个点,以它们连线作为直线计算一次,大概随几百次然后取最大值即可。

T2

CF364D

详见nflscontest877T3。

T3

POI2014Couriers

详见nflscontest877T1。

T4

CodeChef TKCONVEX

一组线段可以拼成多边形的充要条件是 max ⁡ a i ≤ 1 2 ∑ a i \max a_i\leq \frac{1}{2}\sum a_i maxai21ai,这个是显然的,同时还有一件显然的事情就是如果一组线段可以拼成多边形,那么一定可以拼成凸多边形,这里具体就是可以对某个凹进去的角做一个镜像就凸出来了。

同时有一个显然的贪心,就是每个所选的一定是一段连续的,或者是两个人的区间相互交错。

那么我们就有一个随机化思路了,我们给每个点随机标上1或2表示归属哪一个。然后分开O(n)计算一遍即可。这个比较不常见,但是它成功达到了"分离"的效果,使得复杂度指数级下降。

至于正解,是把两个分开处理,一种是两段那么我们就分别枚举两段的起点,是 O ( n 2 ) O(n^2) O(n2)的。另一种是穿插的,我们就枚举一个起点,然后二进制枚举一下每个点是谁的,是 O ( 2 12 n ) O(2^{12}n) O(212n)的。

所以随机化相比正解更好想好写,同时复杂度优秀。

T5

这题一眼随机向量,然后发现最后不够熟练还是不会。。。

先是对于k=2的可以发现就是要算 A ∗ A T A*A^T AAT是不是除了对角线剩下都是1,那么我们就考虑用一个随机向量乘上去,然后在%2意义下判断每个值是否满足条件即可,注意这里要先特殊计算对角线。

对于k=3,我们发现每个位置平方之后%3是1,那么我们相当于先算 B = A ∗ A T B=A*A^T B=AAT,然后算B每一位平方后的每个元,那么我们用一个其余位置都是0,然后对角线有随机值的矩阵乘上去,最后看看算出来的矩阵的对角线是否满足要求,也就是计算 R ∗ B 2 R*B2 RB2。考虑怎么快速计算,我们发现 B = A ∗ A T = ∑ a k , i ∗ a k , j B=A*A^T=\sum a_{k,i}*a_{k,j} B=AAT=ak,iak,j(这里 a i , j a_{i,j} ai,j表示第i个向量的第j个元素),所以 B 2 = ∑ ∑ a k , i ∗ a k , j ∗ a l , i ∗ a l , j B2=\sum\sum a_{k,i}*a_{k,j}*a_{l,i}*a_{l,j} B2=∑∑ak,iak,jal,ial,j,由于我们最后会乘一个对角线的矩阵上去,所以这里有i=j,那么这个计算就是O(nd^2)的了。

给出的edu是可以通过随机赋权,在引入错误率为代价下来简化运算。

T6

CF329C

第一眼感觉是类似哈密顿路的解法,大概是行的,因为这样比哈密顿那题还少个logn,同时是稠密的,所以大概能跑。

题解给出了更为厉害的解法。首先有Ore’s Theorem,就是对于一个含有n个顶点的无向图,有哈密顿回路的充分条件是对于任意两个不相邻顶点u,v,有degu+degv>=n。然后我们就尝试变成强化命题,在补图上找hamiton回路,这里显然每个点度>=n-3,所以也即2(n-3)>=n,那么有n>=6,也就是此时一定有hamiton回路。我们给出一种看似sb的算法,每次随机一个排列,然后看看以此为序作为hamiton回路是否合法,然后不断重复此过程,运用shuffle的话这是O(n)的。然后通过一大通计算(懒得看)发现在n>=9的时候这玩意期望随机次数是<=10的。然后直接开随,n<9的情况可以直接爆搜 C 28 8 ∗ 8 C_{28}^8*8 C2888完全能跑。

这题就是典型las vegas算法。论文给出建议:1.要求合法情况多。2.一般难算,与其计算验证,不如实践检验。3.可以通过卡时来限制次数,变为Monte Carlo。4.如果感觉这题hack的数据不好出,同时没啥事干了,不妨一试。

这里给出一种我感觉的非随机算法。首先如果最大链>=4或者最大环>=5,那么一定这个最大环/链自己就可以变成合法的样子,然后可以通过把其他的插到它们里面使得满足要求(每个边插一个点来使得断绝关系)。所以接下来只探讨最大链<=3且最大环<=4,我们发现如果除去最大(多个去一个),剩下的点数>=2了,那么我们一样可以通过插入来满足要求(如最大环为4时,假设是1-2,2-3,3-4,4-1,可以构建1-3,3–4,4-2,2–1,这里–表示需要插入的)。所以这里随便讨论一下即可,剩下爆搜。但是还有一些细节没有处理(比如一个最大环4,一个最大链4,我们要优先把链插到环里面保证合法),但感觉应该不是很困难。但是既然CF官方题解说了细节巨大多,那么我也肯定没有考虑全

2007国家集训队论文 《浅谈随机化在信息学竞赛中的应用》

上面基本把正常思路介绍完了,这里及以下基本是题。

T1

Geometrical dreams(Ural1046)

我们先看看可以随机什么,然后发现只能随机点。那么我们就随机一个点,然后发现剩下的点坐标都能算了,就是x走一圈得到了x’,要尽量使x与x‘重合,可以用二者距离作为函数来模拟退火,但是更为明智的方法是先算x和x’,然后随机一个dist(y,x’)<=dist(x,x’)的点y,然后用y继续过程,这种方法可以过题。

T2

Two sawmills(CEOI2004)

感觉是熟悉的斜率优化。

然后这是可以模拟退火来解决的。题解给出了一个类似模拟退火,但是更为形象生动的方法。我们把两个伐木场位置合在一起看成一个矩阵,然后随机选几个点,选答案最小的为中心,展开一个边长为原来3/4的矩形,然后递归下去,这种算法像是“阶梯状”的模拟退火,感觉可能不如模拟退火。

T3

NOI2005小H的聚会

感觉就是先一个度限制最大生成树用kruskal跑,这样子没有考虑后效性答案并不对,所以然后每次随机加边断环。

题解还有一种是随机一个不满足条件的最大生成树(由于这题还有向上容错),然后每次随机选一个不满足条件的点,暴力寻找一条合法非树边代替连向这个点的某条边,并且损失最小,满足度限制或者到达运行次数后停止,从头开始多跑几次取最大值。

感觉还是第一种正常人一点。

爬山算法

就是像模拟退火一样,但是更为草率,下一个更优才跳下一个。感觉峰比较少的时候爬山效率不错,会比模拟退火效率高。

自己找的优秀题目

CF1305F

有一说一这道题一眼随机化,但是具体过程挺奇怪。

首先显然只要所有的%p=0即可,我们先尝试p=2。

然后接下来分析一下,假设存在p比2优。接下来要大概计算一些cnt,也就是有多少a%p=0||(a+1)%p=0||(a-1)%p==0,我们知道2的时候的答案<=n,我们一个个数考虑过来,有两种可能,一种是a=kp||a=kp-1||a=kp+1,那么cnt++,一种是a=kp+l,有abs(l)>=2,那么这种最多n/2个,所以即证。

我们每次随机一个ai,然后依次用ai-1,ai,ai+1计算,大概随机20次即可。

P7812

一眼模拟退火,但是这里给出一个提醒,就是我们发现这道题如果每次只是交换相邻元素会存在“坑”,所以是交换两个任意数。注意了,对于这些题目,要看情况,一般来说是交换越随机越好,也可以适当使用先交换任意两个,然后交换相邻的优秀写法。注意了,对于模拟退火题目,由于所谓回退的存在,所以最好是可以记录下最优解。注意了,对于模拟退火题目,贡献的变化计算越快越好,这题可以到O(1)。

P9211

这题想到了确定性算法,没想出随机,对于唯一一篇题解随机的正确性持有保留态度,或者说感觉根本不对。

题解是考虑怎样才能使得这个长度是满足要求的,于是就对于每一个长度len,随机一些位置p(600次),然后计算 s p = s p + l e n s_p=s_{p+len} sp=sp+len的个数,显然这样子越多越好,然后就直接取了最多的那个对应的len作为答案,然后处理出原串。这里对于想要尽量满足要求是可以理解的,但是这样子显然没有保证“最小”的要求,甚至给出的std可以说是找了最多的位置中最多的那一处,这样子我相信是可以卡掉的,但是数据随机的时候大概不是很能卡。

这里给出正确的确定性算法。我们相当于要求出一段前缀和后缀有多少个位置相同,那么我们就枚举字母a,然后使用NTT处理出距离为k的时候有多少对相同的,这十分常见,一共就是 O ( ∣ S ∣ n l o g n ) O(|S|nlogn) O(Snlogn),大概能跑。

P7450

开始变难了。(=我一个写不出来)

首先不考虑中位数的事情。我们考虑如果颜色种数比较少怎么办,甚至就是说c=k,我们可以想到每种颜色用一个超源向巧克力连边,然后跑最小斯坦纳树(这个真的不熟)。考虑种数变大怎么办,我们如法炮制,把每种颜色随机映射到1-k,这样子就可以说是“一次性处理多个情况”,更好的是,我们考虑最优解情况下的五种颜色,在不同的映射权值时我们就可以计算出最优解,那么概率就是 k ! k k \frac{k!}{k^k} kkk!,k=5时,这个是0,0384,那么我们期望在 1 / 0.0384 1/0.0384 1/0.0384步就可以得到,具体就是,大概200次就一定有答案了。如果多了一个中位数,那么我们二分中位数即可。

这种思路真的非常edu,是随机化里鲜见的想法。

P9376

紫题真是越来越难了。

我们考虑这个相当于是什么,可以发现就是字典树上,取一个点,使得所有点到它的总距离和最小,考虑暴力贪的时候,对于一条边,它的儿子的子树大小一定要比上面部分大才能跳下来,所以可以发现最后的点对应的前缀,一定是至少n/2个点的前缀。

所以考虑随机一个数然后依次计算它的每个前缀的答案。我们发现这个也可以对应到字典树上,具体就是计算一条链上的 s z x − s z s o n x sz_x-sz_{son_x} szxszsonx,我们发现计算 s z x sz_x szx就是要求权值在一个范围,所以可以主席树做,最后一个前缀和回去。随机次数大概在logn的级别,所以一共是 O ( n l o g 3 n ) O(nlog^3n) O(nlog3n)

你可能感兴趣的:(c++)