A. Automatic Sprayer 2
只能膜拜孔姥爷,换我肯定找不全方程。
设每一行的和为 (R_i),每一列的和为 (C_i),那么有:
考虑二次差分,会发现:
(R_i) 同理,那么我们只差 (R_1,R_n,C_1,C_n),没有求出来。
然后再通过 (E_{x,y}) 的定义列方程:
可以继续列出 (R_1,C_n),(R_n,C_1),然后发现第四个其实可以通过前三个推出来 (是否等价其实就看未知数,第四个方程的未知数完全可以用前三个组合出来,所以是线性相关的),所以我们还缺一个方程。然后加上很容易被忽略的 “行之和等于列之和” 即可搞出出新的未知数组合。
构造出行之和与列之和以后直接贪心即可。
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=min(r[i],c[j]),r[i]-=a[i][j],c[j]-=a[i][j];
只要行之和=列之和这样的构造就是合法的,因为如果有在某一行填完的时候这一行的 (r_i) 还有剩余,那么说明前 (i) 行的和大于列总和,矛盾。
B. Cilantro
首先有一个很显然的结论,如果对于一个入栈序列,一定能达成任何 0/1 个数与其相等的出栈序列。因为我们可以保证栈中只有 1 种元素,这样未进栈的第一个和栈顶一定是两种不同的元素。
第二个很显然的结论:在满足 (S_i=T_1,S_j=T_1,i<j) 时,若 (j) 可行,那么 (i) 一定可行,所以我们只要找到最右的可行点即可。
考虑第一个点的出栈点设其为 (x),在此时栈为空,所以相当于拆成了两个子问题,其中要满足 (S_{2..x}) 与 (T_{1..x-1}) 0/1 个数相等。那么同理,第二个点就是在第一个出栈点的左边再找一个满足此类似条件的出栈点。容易发现,我们贪心让出栈点靠右是正确的,所以双指针扫一下就行了。
C. Equivalent Pipelines
两个树相同,当且仅当从大到小加边(边权相同的一起加),每次合并的点集都相同。
可以用哈希,每次合并的权值就是两边点集权值和的乘积再乘上边权。每次合并权值都相等就行。
D. Flowerbed Redecoration
考虑置换。
把平移板子看成整个矩阵反着循环位移
设 (cal{F}) 为旋转 ({[1,d],[1,d]}) 的置换,(cal{G}) 为整体向左平移的置换,(cal{H}) 为整体向右平移的置换。那么行操作的置换就是 (cal A=(cal Fcirccal G)^icirccal F)。整体的置换就是 ((cal Acirccal H)^icirccal A)。
快速幂。
E. Goose Coins
先讲一下我场上的 (dp):
考虑 (p) 的贪心分解:即记 (a_i=(p \% c_{i+1})/c_i),如果有解一定有 (sum a leq k)
设 (f_{i,j}) 表示搞出一个 (c_i) 用 (j) 个硬币的最大/最小代价,可以做一个背包,最坏复杂度为 (O(k^3log_{1000}V))
然后直接用贪心分解再跑一个背包,复杂度 (O(k^3)),可以通过。
下面是 (nk^2) 的做法:
(f_{i,j,k}) 表示从后往前到 (i),填了 (j) 个,当前剩余 (rest/c_i=k) 。这样是 (nk^3) 的,但是发现 (i,j,k) 和 (i,j-c_i/c_{i-1},k+1) 往下贡献的位置都是相同的,所以处理一个后缀 (min/max) 即可。
F. Hedgehog Graph
有点难,只讲一下 (2 sqrt V + logV) 的做法吧:对于所有 (i in [1,sqrt V]),询问 ((s,i)) 和 ((s,sqrt V i)),发现任意一个 ([1,V]) 的数都可以表示成两个数之差,所以一定能找到相同点。
找到环长的倍数以后试除每个因子即可。
G. Lamb's Respite
拆成三段,即使初始血量不等于 (H) 也可以看成 (H) 然后加上一个 (-x) 。
直接维护区间的最小子段和,最小后缀和,最小后缀和是最后一个顶到 (H) 的位置,最小子段和是最容易触底的地方。
如果不是锁血的话,那么处理出最小子段和的终止节点,后面任意前缀和一定 (>0) ,只要考虑上界即可。
H. Or Machine
签到题。对于每一个二进制位考虑,其实就是一个对于操作时间跑最短路。
J. Periodic Ruler
签到题。首先把每一对的因子干掉,然后再对于 (1 sim n) 把不同余数拍到一起看看是否必然有更小周期。
K. Three Competitions
孔姥爷的做法:
对于每个点求出它的直接出边的度数。
很显然这是一个竞赛图,对于竞赛图有一个性质就是可以通过出度得到 (scc) 。
具体地,对于度数排序,在缩点后的图中后面点的出度一定大于前面的出度,所以 (scc) 一定是一个区间。
从后往前搞,去掉最后一个环必须要满足剩下的点满足总出度 = (frac{n(n-1)}{2})。从后往前扫一遍即可。
复杂度 (O(nlog^2n)) 或 (O(nlogn)) ,取决于三维偏序的实现复杂度。
MYY 的做法:
有一种非常神仙的 (scc) 求法,即直接暴力 (dfs),然后记下出栈序列。
然后对于出栈序列从后往前扫,在反图上再暴力 (dfs),找到的点就同属于一个 (scc)。
问题在于怎么找出边,相当于分成 3 个图,每个图就是一个平面每次要找到一个在这个点左下的点。
对于第一维建立线段树,维护在第一维 ([l,r]) 区间中第二维的最小值,然后就可以删了(为啥我只能想到树套树。。)