前言
会在题目名称后给每道题目一个标记,标 !
的是我认为非常好的 CNOI-Style 的题,标 *
的是构造题、结论题等比较 Ad-hoc 的题,标 +
的是思维含量比较高题。根据牛牛程度会增减数量。
QOJ6345 Random Interactive Convex Hull Bot [**+]
考虑增量构造,每次加入一个点 i 时,任意选凸包上的一个点 s,找到距他凸包大小一半的点 t,询问 (s,t,i) 即可得到 i 在直线 st 的哪一边,然后将 s 和这边的凸包上的点连线将这个半平面划分成若干部分,此时可以二分出 i 在哪一部分。
之后直接把 i 两侧要删掉的点弹弹掉就好了。
CFgym104065B Call Me Call Me(2022 CCPC 绵阳)
考虑所有区间都有交怎么做。
那按交把整个序列划分成两部分,对于每一部分把每个区间按端点排序(右半部分按右端点从小到大排序,左半部分按左端点从大到小排序),然后对于每一半的每个元素给他一个 k/2 的权值,每次更新就是把所有包含它的区间的权值都 −1,然后取出所有权值变成 0 的区间 check 一下是否满足条件,不满足就把两边都设成当前还需要的个数 /2。
这个东西应该叫折半报警器?然后这样每个区间被 check 的次数就是 O(logn) 的。
然后考虑更一般的情况。
设初始区间为 [1,n],在区间中间设一个点,然后把区间划分成两部分递归下去。然后对于询问的每个区间就把他挂在第一个被他包含的点上。这样复杂度就是 O(nlog2n)。
洛谷 P7111 青春有悔
先变成求总分 <y 的方案数。
设:
F(x)=1−x1i=1∏n1−x1−xai+1
在不乘前面的 1−x1 时其 i 次项系数就是总分为 i 的方案数,乘上之后就是前缀和,即总分 ≤i 的方案数。
F(x)=1−x1i=1∏n1−x1−xai+1=(1−x1)n+1i=1∏n(1−xai+1)
对于前半部分可以归纳证明得到:
(1−x1)n+1=i=0∑∞(in+i)xi
对于后半部分,先 ln 一下:
ln(i=1∏n(1−xai+1))=i=1∑nln(1−xai+1)=i=1∑nj=1∑∞−jx(ai+1)j
对每个 k 求出 ai+1=k 的个数可以调和级数求出每一项系数,然后 exp 一下就好了。
接着考虑一个询问 p,b,y+1,那么答案就是:
[xy]1−xap+11−xb+1F(x)=[xy]1−xap+11F(x)−[xy−b−1]1−xap+11F(x)
因此问题就转化成求 [xy]1−xa1F(x)。
根号分治一下,对于 a>B,暴力卷积,复杂度为 O(nBn),对于 a≤B,预处理出所有系数,复杂度为 O(nB)。取 B=n,时间复杂度为 O(nn)。
tips:这里认为 n,q 和值域同阶。
AGC062B Split and Insert [!++]
考虑把操作倒过来,就是选择一个子序列提出来放到最后,然后要从目标排列变成有序的排列。
设 fi,l,r 表示第 i 次操作前值域 [l,r] 已经排好序的最小代价,则:
fi,l,r=min{fi+1,l,r∪{fi+1,l,k+fi+1,k+1,r+ci(r−k)∣l≤k<r}}
初始状态就是 fm+1,l,r=0,要求目标状态值域 [l,r] 的数是排好序的。答案就是 f1,1,n。
CF1874E Jellyfish and Hack [!]
设 fi,j 表示长度为 i 权值为 j 的排列的方案数,有如下转移:
fi,j=k=1∑i(k−1i−1)l=0∑j−ifk−1,lfi−k,j−i−l
暴力转移是 O(n6) 的。
考虑设 Fi(x)=∑j=0i(i+1)/2fi,jxj,显然是最高 n(n+1)/2 次多项式,带 n(n+1)/2+1 个值进去插一下就好了,每次转移是 O(n4) 的,插值后还原多项式也是 O(n4) 的。
CF1758F Decent Division [!!]
考虑对于为 1 的每个位置 i,设 to(i) 表示最小的区间使得 [i,to(i)] 是一段合法区间。即:令 1 为 1,0 为 −1,设 si 为前缀和,则 to(i) 是最小的满足 sto(i)=si−1 的位置。
每次操作位置 i 使得 0→1 时,若 i 不被区间包含,则令 p=i,否则令 p=l 为包含它的区间的左端点,然后加入 [p,to(p)],再删除与之相交的区间。这样调整完就合法了,因为所有 [i,to(i)] 的区间要么包含要么相离。
每次操作 1→0 时,找到区间左端点 l,删掉区间,然后不断找到 l 后第一个 1 的位置 p,加入 [p,to(p)],然后 l←to(p)+1,直到 p>r。
正确性显然,但是时间有点问题,区间可能被拆成很多个,一个简单的 hack 是:操作 1,3,5,7,…,然后一直操作 2。
解决办法是令 to(i) 为满足 sto(i)=si−1 且 ∀j∈[i,to(i)),sj≥si−1 的最大位置,这样每次拆区间后都会在区间下一位留下一个 0。新选择的区间的总和相较于原区间至多 −2,因此最多留下 2 个 0,因此至多被拆成 3 个区间。
CF1874D Jellyfish and Miku [!+]
设 fi 表示从 i 走到终点的期望步数。
⎩⎪⎪⎨⎪⎪⎧f0=1+f1fi=1+ai+ai+1aifi−1+ai+ai+1ai+1fi+1fn=01≤i<n
第二个式子化一下:
ai+1(fi−fi+1)=ai(fi−1−fi)+ai+ai+1
设 gi=fi−1−fi,则:
{g1=1aigi=ai−1gi−1+ai−1+ai
可以归纳证明:
gi=2×aij=1∑i−1aj+1
答案即为:
f0=i=1∑n(fi−1−fi)=i=1∑ngi=i=1∑n⎝⎜⎜⎜⎜⎛2×aij=1∑i−1aj+1⎠⎟⎟⎟⎟⎞=n+2i=1∑nai1j=1∑i−1aj
只要最小化后面那个东西即可。
设 dpi,j 表示前 i 个,a 的和是 j 时的答案,有如下转移:
dpi,j+k←dpi,j+kj
直接来是 O(nm2) 的,但是再仔细分析可以发现 a 一定是单调不降的,因此转移时需要保证 j+k(n−i+1)≤m,这样复杂度就变成了:
O(i=1∑nj=0∑mim−j)=O(i=1∑n2im(m+1))=O(m2logm)
CF512E Fox And Polygon [*]
操作可逆,所以把两个凸包都变成所有弦都与 1 相连。具体就是顺时针枚举每个点,然后对未符合要求的操作对角线。
CF1707E Replace [!!++]
咕了。