TJOI2015 旅游
md读错题了。题意其实是每次旅游只能买卖一次。那不就是sb题了。
考虑树剖,然后维护链上的最大值,最小值,从左往右走的答案,和从右往左走的答案。合并的时候也比较简单。唯一要注意的一点是计算最终答案的时候要严格从左往右,所以会麻烦亿些。
HEOI2015 兔子与樱花
贪心。每个节点贪心选择权重最小的子节点删。不用考虑删除 v 后 v 再删除 v 的子节点的问题,因为如果可以删 v 和 v 的子节点那么早就应该在 v 处删掉了。
TJOI2015 线性代数
\(A_{1,k}\) 取 \(1\) 会有 \(C_{1,k}\) 的代价,\(A_{1,j}\) 和 \(A_{1,k}\) 都取 \(1\) 会有 \(B_{j,k}\) 的贡献。
最小割,建点 \(P_{i,j}\) 表示选择 \(A_{1,j},A_{1,k}\),建边 \(S\stackrel{c_i}{\longrightarrow} i\stackrel{\inf}{\longrightarrow} P_{i,j} \stackrel{B_{i,j}}{\longrightarrow}T\)。
AGC028D Chords
把环拆成链,发现连通块必然不会相交,只会相离或者包含。于是可以用一个区间 DP,\(f(i,j)\) 表示 \(i,j\) 处于同一极大连通块(不存在向外的边),考虑 \([i,j]\) 中的点的连边情况方案数。直接做不好做,考虑容斥掉 \(i,j\) 同一连通块的方案数。
用 \(g(x)\) 表示对于目前无边的 \(x\) 个点,有多少种匹配连边方案。若 \(x\) 为奇数那么显然为 \(0\),否则应该有 \(g(x)=(x-1)!!\),相当于每次一个点选择自己的连边对象后都会少掉两个点。
用 \(cnt(i,j)\) 表示 \([i,j]\) 中有多少点的连边对象未定。容斥可以直接容斥 \(i\) 和哪个点组成极大连通块,于是有
答案直接统计对于每一个连通块对答案的贡献,即
https://atcoder.jp/contests/agc028/submissions/28295507
AGC010D Decrementing
一个很有意思的一点,这题看上去和最大公约数最有关系,其实是和奇偶性关系最大。这是因为 -1 这个条件,对一个数影响最显著的在于其奇偶性。
如果不存在除以gcd,那么就看 \(\sum a_i-1\) 的奇偶性。如果为奇数,那么先手必胜;否则后手必胜。
然后是一个非常有趣的事情:奇公因数并不影响大局。于是乎如果有奇数个偶数那么先手必胜。这样考虑就和第一个差不多。
否则,先手就必须希望能破局来避免让后手拿到必胜局面,于是乎会希望场面上有且仅有一个奇数,于是他会去把那个奇数 -1 然后全部除以偶数,然后碰碰运气。否则后手必胜。
https://atcoder.jp/contests/agc010/submissions/me
AGC024E Sequence Growing Hard
考虑增->删,即从 \(a_n\) 删到 \(a_0\)。首先连续的重复的元素是没有价值的,考虑先看做一个元素,则我们必须删除的是满足大于自己后面的元素。
这类 DP 需要考虑如何避免重复。\(f(i,j)\) 表示长度为 \(n\),元素 \(\in[1,k]\) 的答案。考虑枚举最小的元素(\(1\))的出现位置和删除时间。为了保证不重复,出现位置必须保证这个位置之前没有 \(1\);为了保证合法,这个之后的必须在删除 \(1\) 之前删完。
于是有
后面一个求和与 \(j\) 无关,\(O(n^3)\) 预处理即可。
https://atcoder.jp/contests/agc024/submissions/28297926
CF1612G Max Sum Array
设第 \(i\) 个值为 \(p\) 的元素的位置为 \(c_{p,i}\),则
对于每个值,都有 \(c_p\) 个系数(\(c_i-1,c_i-3,\dots,-c_i+1\)),对于这总共的 \(n\) 个系数,运用一下排序不等式即可。由于并没有 \(\sum c\) 的限制,但是实际上不同的系数最多 \(2c\) 种,于是看每种系数有多少个即可。
https://codeforces.com/contest/1612/submission/141410167
AGC027E ABBreviate
将 \(a\to 1\),\(b\to 2\),则无论怎么变换 \((\sum s_i)\mod 3\) 是不会变的。
可以归纳证明,\(S\) 可以变换成 \(a\) 当且仅当其总和 \(\text{mod }3\) 为 \(1\) 且并不是 \(\texttt{abab...ba}\) 的形式(因为这样不可操作)。对于变换成 \(b\) 的情况同理。
于是乎,\(S\) 可以变换成 \(T\) 可以贪心匹配,选择一段最小的前缀变换成 \(T_1\),然后删掉后继续匹配 \(T_2\) …… 直到最后剩下一段总和模 \(3\) 余 \(0\) 的一段后缀和 \(S\) 匹配。所以我们可以想象成分成 \(|T|-p\) 段变换成一个字母,加上最后一个长 \(p\) 的后缀段。
证明其充分必要很复杂。所以直接意识流掉了。
首先特判无法操作的情况。否则设计 \(f(i)\) 表示对于 \(S[i,n]\),有多少合法分段方案。
其中 \(g_x(i)\) 表示最小的后继 \(j\) 满足 \([i,j)\) 区间和的模 \(3\) 的余数为 \(x\)。
由于转移包括了空串,答案要减掉。
https://atcoder.jp/contests/agc027/submissions/28345196
ARC058C Iroha and Haiku
问题最大的地方在于这个条件非常容易导致算重。考虑状压,由于 \(X+Y+Z\le 17\),看看能不能状压。
有一个非常有意思的状压:由于有序整数拆分不会超过 \(2^{n-1}\) 种,所以一种拆分方案可以一一对应一个二进制状压。考虑这样表示:对于第 \(i\) 位,若为 \(1\),则代表拆分后存在一个后缀和为 \(i\)。这样做是考虑到 DP 时的方便。合法相当于存在某一个时刻的状压,第 \(Z\),\(Z+Y\),\(Z+Y+X\) 位为 1。\(S\) 要加入一个数 \(x\) 相当于让原状态左移 \(x\) 位,然后加上 \(2^{x-1}\)(设其表示为 \(S*x\))。
为了不用在 DP 中检测存在性,直接补集转换。\(f(i,S)\) 表示填到第 \(i\) 个数,靠近自己的划分为 \(S\) 的不存在 \(X,Y,Z\) 划分的方案数。设 \(g(S)\) 表示 \(S\) 是否满足其为 \(X,Y,Z\) 的划分。
答案即为 \(10^n-\sum_s f(n,s)\)。
https://atcoder.jp/contests/arc058/submissions/28356802
ARC059C Children and Candies
假如 \(x_i\) 已经全部确定,那么可以 DP:\(f(i,j)\) 表示前 \(i\) 个人拿走 \(j\) 颗糖的值,则有
我们看到这个 \(x\) 的变化每个人都是独立的,所以加入后就变成了,所以令 \(g(i,j)\) 表示 \(\sum_{k=A_i}^{B_i} k^{j}\),则有
https://atcoder.jp/contests/arc059/submissions/28357464
ARC060D Best Representation
考虑先找到循环节,这个可以随便找。然后分类讨论。
-
无循环节
那答案必然是拆成一个串即可
-
循环节长度为 \(1\)
那答案必然是全部拆开
-
循环节长度 \(>1\)
拆分数一定 \(=2\)。如果一个串不是全部相同的串,那么必然可以拆分成两个无循环节的串(可以用反证法证明,如果所有前缀都有循环节,那么意味着整个串的循环节长度为 \(1\))。所以前后两次 KMP 判断前缀后缀循环节然后枚举分割点即可。
https://atcoder.jp/contests/arc060/submissions/28369432
ARC061C Snuke's Subway Trip
首先我们发现一个公司包管的线路可以组成一些连通块,但是这些不同连通块之间完全可以考虑成不同公司。所以可以化简成每个公司只会包管形成一个连通块的子图,即每个公司包管的点可以互通。这里一定需要注意复杂度不能假,必须把所有公司拆开来考虑,对每个公司内部进行一个再拆分。这样才能保证每个点被访问 \(O(\deg )\) 次,即总共(如果用并查集的话)复杂度为 \(O(m\alpha)\)。(我代码实现中为了简便做了一个简单的去重多了个 \(\log\),实际上可以不需要,而且这个并查集也是可以用线性的 dfs 解决掉的,不过不影响大局)。
容易发现我们乘车相当于不断地换乘,每次换成永远是 \(1\) 元。对于这种情况,可以建立一些辅助点,每个点代表一个公司(的连通块),然后所有其联通的点以 \(\frac{1}{2}\) 的边权与它相连,然后跑一个最短路即可(这样每次出入都是 \(1/2\),所以进行一次换乘的代价就是 \(1\))。
每个点连的额外边最多为 \(\deg(u)\),然后原图上的原边是可以去掉的,也就是说新图总边数 \(\le \sum \deg(u)=2m\),总点数 \(\le m+n\)。还有实际操作的时候由于边权全是 \(1/2\) 所以先当 \(1\) 来做最后全部除以 \(2\) 即可。
https://atcoder.jp/contests/arc061/submissions/28443592
ARC061D Card Game for Three
最直观的就是考虑到 \(A\) 一定拿走 \(N\) 张,于是枚举 \(B,C\) 拿了几张。
然而这个式子中无论怎么弄后面仍会有个 \(3\) 的幂次,很烦,纯组合数可能看上去更好看一些。于是改为枚举 \(m+k\) 和 \(k\)。令 \(S=M+K\)。
第二个 \(\sigma\) 那里是一个对下指标的一个区间求和,没法直接推式,考虑递推,设 \(f(i)=\sum_{j\in\{i-M,K\}} \binom{i}{j}\),我们需要找到其与 \(f(i-1)\) 的关系。首先套路拆组合数,然后提出 \(f(i-1)\) 即可:
于是递推出 \(f(i)\) 后求 \(ans=\sum_{s=0}^{S}3^{S-s}\binom{s+n-1}{n-1}f(s)\) 即可。
https://atcoder.jp/contests/arc061/submissions/28453159
LOJ6029 雅礼集训2017Day1 市场
一个有用的小技巧:除法下取证,必定会让极差减半;而加法不会让极差改变。于是维护区间最小最大和加法。
如果区间的 \(\max-\lfloor\frac{\max}{d}\rfloor=\min-\lfloor\frac{\min}{d}\rfloor\),那么区间除法可以直接用减法代替;否则继续递归。
每次区间加会让线段树上的 \(\log n\) 个节点的极差增加 \(v\),于是会多递归 \(\log n\log v\) 次,所以总复杂度为均摊 \(O((n+q)\log n\log v)\)。
LG5068 Ynoi2015 我回来了
对于 \(d\) 的伤害,设次数最大为 \(k\),那么首先必须有人的血量在 \([1,d]\) 中,然后必须会有人的血量在 \([d+1,2d]\) 中……我们考虑对于每个伤害 \(d\),对序列分成 \(n/d\) 个段,分别为 \([1,d],[d+1,2d],\dots,[d\times \lfloor\frac{n}{d}\rfloor+1,n]\),设 \(p_{d,i}\) 表示伤害 \(d\) 的第 \(i\) 段(\([(i-1)\times d+1,i\times d]\)),则总计可以考虑成 \(O(n\log n)\) 个段(调和级数)。
对于 \(d\) 的伤害,其的答案即为最大的 \(k\),使得 \(\forall i\le k,\) 存在血量 \(\in p_{d,i}\) 的人。设 \(t_{d,i}\) 表示最小的时间点满足区间 \(p_{d,i}\) 有人,\(c_i\) 表示最小的时间点满足存在血量 \(i\) 的人,于是乎有 \(t_{d,i}=\min_{j\in p_{d,i}} c_i\)。考虑 \(t\) 的一个关于 \(i\) 的前缀最大值 \(s\),其意义为对于 \(d\) 的伤害至少有 \(i\) 次最早的时间点。处理 \(c,s,t\) 可以做到 \(O(n\log n)\)。
离线后可以考虑每个 \(p_{d,i}\) 中的贡献,发现:对于问询 \((time,L,R)\),对其产生贡献的是满足 \(time>s_{d,i}\) 且 \(d\in[L,R]\) 的区间。对时间进行扫描线,然后继续做就行了。
如果动态更新这个 \(s\) 的话可以做到在线。不过反而更加麻烦。
https://www.luogu.com.cn/record/66599472
APIO2018 Duathlon
建出圆方树,考虑枚举中间点 \(x\),将它作为根,设 \(f(u)\) 表示在 \(u\) 的子树中,有多少形如 \(x\to u\to y\) 的路径。设 \(s_u\) 表示子树内圆点个数,则有
其中方点的转移是因为要考虑到方点中 bcc 的每个点都可以作为中转点。换根得到 \(s\) 然后计算 \(f\) 之和即可。
数列分块入门
-
数列分块入门1
-
数列分块入门2
我们需要块内维护一个有序的结构,每次修改边角时暴力重构块内排序即可
-
数列分块入门3
-
数列分块入门4
一定要注意每一个块的初始化!
-
数列分块入门5
每个块记录是否为 \(01\) 块,所以一个块只会被全局改 \(O(\log\log n)\) 次。
-
数列分块入门6
插入暴力修改块,然后根号暴力重构。
-
数列分块入门8
暴力分块做即可,复杂度是均摊的。
-
数列分块入门9 / LG4168 蒲公英
处理 \(f(l,r)\) 表示第 \(l\) 块到第 \(r\) 块的众数,和一个前缀块的桶 \(c(x,y)\) 前 \(x\) 的块 \(y\) 的出现次数。表示然后每次询问就只需要求 \(O(\sqrt n)\) 个元素的众数即可。
HNOI2010 弹飞绵羊
将序列分块,对于每一块处理出 \(f(i)\) 表示从 \(i\) 开始跳 \(f(i)\) 步后跳出这一个块,\(g(i)\) 表示跳 \(f(i)\) 步会跳到什么地方。处理一个块的 \(f,g\) 需要 \(O(B)\) 步,进行一次问询需要 \(O(\frac{N}{B})\),取 \(B=\sqrt n\) 即可。
https://hydro.ac/d/bzoj/record/61e4e40486fb00d2d0805b1e
Ynoi2007 rfplca
Ynoi 中不多有的小清新分块。考虑记录 \(f(i)\) 表示 \(i\) 不断跳然后跳出当前块之后到达的第一个点,然后求 \(lca\) 和树剖差不多。先看跳 \(f\) 上去后的块是否相同,不相同就跳块;再看跳 \(f\) 上去的点相不相同,不相同也跳块;否则都在块内直接跳父指针。
然后考虑修改。这个不大好操作,看有没有均摊的性质。发现父亲指针只会减(前移)。对于一个块,如果被改了 \(O(\sqrt n)\) 次,那么我们发现所有的元素的父亲指针都一定在块外了,于是此时我们只需要在块上打一个减法标记就可以 \(O(1)\) pushdown 一个位置得到其真实父亲指针。如果没有加满那么暴力重构块内的 \(f\) 指针即可,总复杂度 \(O(n\sqrt n)\) 且不卡常。
https://www.luogu.com.cn/record/67004933
ARC063C Integers on a Tree
考虑维护出每个点仅考虑子树可以取到的值,发现其必然是一个区间内奇偶相同的值,于是记录这个区间及其奇偶性然后判断一下即可。
https://atcoder.jp/contests/arc063/submissions/28611506
ARC064C Cosmic Rays
这个 \(n\le 1000\) ,发现这题很水,处理出两两距离然后跑一个最短路即可。
https://atcoder.jp/contests/arc064/submissions/28626394
ARC064D Rotated Palindromes
这题可以直接考虑变化带来的贡献,因为对于每一个可以得到的非循环数列都可以唯一确定其初始的循环数列,重复发生当且仅当一个回文串经过移动后变成了另一个回文串,即一个回文串是另一个的循环位移。先将这个回文串拆成自己的一个循环节(也是一个回文串),我们发现当且仅当这个循环节是偶回文串才会出现回文循环位移(把循环节长度的一半的前缀扔到后面去)。一个最小循环节可以一一对应一个长 \(n\) 的串,于是设最小循环节长度为 \(m\)。若 \(m\) 为奇则其对答案的贡献为 \(s(m)=m\);若 \(m\) 为偶则其对答案的贡献为 \(s(m)=\frac{m}{2}\)。
然后就是数长度为 \(m\) 的最小回文循环节的个数。设 \(f(m)\) 表示这个个数,我们可以容斥一下,于是有
时间复杂度 \(O(d^2(n)\log K+\sqrt n)\)。
https://atcoder.jp/contests/arc064/submissions/28627100
CF551C GukiZ hates Boxes
二分答案,发现人不多,考虑在给定时间下每个人的决策。每个人所用时间为其走过的路程加上搬的箱子数。于是我们按由远及近的顺序贪心安排(因为我们知道最大的路程)。
http://codeforces.com/contest/551/submission/143565113
CF570D Tree Requests
对字母进行状压。区间可以构成回文串等价于区间内所有状态异或起来得到的位数 \(\le 1\)。然后考虑按深度维护 dfs 序,然后就可以二分出以 \(a\) 为根的子树中深度为 \(b\) 的点了。
http://codeforces.com/contest/570/submission/143568558
ARC063D Snuke's Coloring 2
答案的下限是 \(2\times \max(W,H)\)(在某个位置选成长条的即可)。所以若矩形不过某个中线,那么所得结果 \(<W+H\le 2\times \max(W,H)\)。所以矩形一定过 \(x\) 轴或 \(y\) 轴的中线。
然后,我们假设是过 \(x\) 轴中线,于是每个点就可以固定成一个 \(y\) 的限制(比如若 \(x<\frac{W}{2}\) 就等价于限制区间 \([x,H]\))。这样就可以对 \(y\) 排序后进行扫描线。
(为了方便我们换一下 \(x,y\))沿着 \(y=H/2\) 从左往右扫描线,希望能算出每个点在 \(y\) 上的最大长度,并且求出以其作为矩形的右边的答案。此时真正右边长度的答案应该是左边到右边这段区间中的一个区间最小值(也就是当前时间的后缀最小值)。于是用一个单调栈套线段树:单调栈维护这个最小值,然后单调栈每次改动的时候会存在一个区间使得其作为左边的答案发生变化,这个用线段树操作,最后查询一下即可。
做两次的话,每个点交换横纵坐标即可调用相同函数。
要注意特判上述“一条线”的特殊情况(即对于相邻两个点,宽度为两个点间 \(x_i-x_{i-1}\),长为 \(H\) 这种的情况)。
https://atcoder.jp/contests/arc063/submissions/28811399
CF559C Gerald and Giant Chess
\(f(i)\) 表示到达第 \(i\) 个黑点且之前的黑点都不踩的情况数,\(d(i,j)\) 表示 \(i\to j\) 的路径数,可以组合数算出。
https://codeforces.com/contest/559/submission/143824661
CF618F Double Knapsack
很有意思的一题。不知道是怎么想到的。
下证明必存在 \(A\) 和 \(B\) 的两端区间使得其和相等。
考虑其前缀和数组 \(S\) 和 \(T\)。不妨设 \(S_n\le T_n\),则可以设 \(p_i\) 表示最大的 \(j\) 满足 \(T_j\le S_i\),并且有 \(p_i<n\)。根据定义,我们有 \(A_{i}-B_{p_i}<B_{p_i+1}\le n\),于是对于 \(A_{0}-B_{p_{0}},\dots,A_n-B_{p_n}\) 这 \(n+1\) 个值中必有两个 \(A_i-B_{p_i}=A_j-B_{p_j}\),即 \(A_i-A_j=B_{p_i}-B_{p_j}\),是两端相等区间。
https://codeforces.com/contest/618/submission/143829319
AGC010E Rearranging
找到图论模型是一个很好的方法,因为不少图论东西有很直观的可以大胆猜想不用证明。
首先容易发现对于不互质的两个数,一旦在先手定下顺序后,两者先后顺序必然不会改变。利用这点可以想到 DAG 的拓扑序,于是乎我们在不互质的两个数建边,可以得到 \(O(n^2)\) 条边。于是这就是一个先手给边定向,然后后手找到一个最大拓扑序的问题。
找最大拓扑序是一个简单的问题,即每次找到最大的零度点。先手的问题是希望最大拓扑序最小。贪心地去设置边:在 DFS 的时候每次贪心找到最小的点去连。容易证明这样是正确的。关于连边,连到一个生成树即可,因为对于祖先->孩子的连边必然是没有必要的(后手在朝那里走的时候祖先早已走过了)。
复杂度 \(O(n^2\log V)\)。
https://atcoder.jp/contests/agc010/submissions/28770166
ARC133
A
考虑第一个 \(a_i>a_{i+1}\) 的元素,把它删掉一定最优。
https://atcoder.jp/contests/arc133/submissions/28780302
B
注意到是 PERMUTATION,于是有一个有意思的小技巧。题目可以转化为有 \(O(n\log n)\) 个 pair \((i,j)\) 满足 \(a_i\mid b_j\),然后找满足 \(i,j\) 同时上升的最长子序列。
按照 \(i\) 从小到大排序,\(i\) 相同的按照 \(j\) 从大到小排序,然后就是一个关于 \(j\) 的 LIS 了。
https://atcoder.jp/contests/arc133/submissions/28786955
C
首先有无解情况为 \(\sum a\not\equiv \sum b\)。然后考虑先把所有数都填上 \(K-1\),考虑减掉一些数。那么我们减去数的下界为 \(\max \sum c, \sum d\),其中 \(c,d\) 分别为每一行/列中需要减少的最少总量。
然后用构造证明下界是可以取到的。我们希望 \(\sum c\) 和 \(\sum d\) 可以想等使得我们做起来更加简便,于是我们给 \(c_1\) 或 \(d_1\) 加点 \(k\) 的倍数即可。然后我们不断找 \(c,d\ge 1\) 的格子,减一直到 \(c,d\) 全部变成 \(0\)。构造完毕。
https://atcoder.jp/contests/arc133/submissions/28788524
D
异或前缀和有个性质:
于是乎我们只需要分类讨论一下。