Blank
定义dp[i][j][k][t]代表填完前t个位置后,{0,1,2,3}这4个数字最后一次出现的位置,排序后为i,j,k,t(i<j<k<t)的方案数目,则按照第t+1位的数字的四种选择,可以得到四种转移。
对于限制可以按照限制区间的右端点分类,求出dp[i][j][k][t]后,找到所有以t为区间右端点的限制条件,如果当前状态不满足所有限制条件则不合法,不再向后转移。
总时间复杂度O(n4)。滚动一维,空间复杂度O(n3)
UPD 一开始的模数为109+7,后来统一改成了998244353,但最后在polygon上生成数据的时候标程放错了,就跑出了模109+7的结果。对被这道题卡了的大佬们表示歉意!
Operation
暴力的做法可以用数据结构维护区间线性基,但肯定过不了。
贪心地维护序列的前缀线性基(上三角形态),对于每个线性基,将出现位置靠右的数字尽可能地放在高位,也就是说在插入新数字的时候,要同时记录对应位置上数字的出现位置,并且在找到可以插入的位置的时候,如果新数字比位置上原来的数字更靠右,就将该位置上原来的数字向低位推。
在求最大值的时候,从高位向低位遍历,如果该位上的数字出现在询问中区间左端点的右侧且可以使答案变大,就异或到答案里。
对于线性基的每一位,与它异或过的线性基更高位置上的数字肯定都出现在它右侧(否则它就会被插入在那个位置了),因此做法的正确性显然。
Milk
由于只能从上向下走,因此可以将行离散化,然后从上向下做背包。
记第i行的牛奶数为ci,则对于第i行,求出在行内向左/右走喝1,2,...,ci包牛奶并且回到/不回到行中点的最短时间,然后合并背包求出在第i行内喝1,2,...,ci包牛奶并且回到/不回到行中点的最短时间,然后和在前i−1行喝牛奶并回到中点的背包合并,求出在前i行内喝1,2,...,k包牛奶并且回到/不回到行中点的最短时间,并用不回到中点的背包更新答案。每一行处理的复杂度为O(kci),因此总复杂度为O(k2)。
注意对第一行要特殊处理。
Vacation
把第i辆车追上第i+1辆车当作一个事件,显然只有n个事件,且第i辆车追上第i+1辆车只可能会对第i−1辆车追上第i辆车的时间产生影响,且时间一定是变小,因此可以维护车之间的距离和速度来计算事件发生时间,用堆来找出最早发生的事件,不停处理直到0车通过停车线。复杂度为O(nlogn)。
上述做法比较麻烦,可以直接二分最终时间,然后从第一辆车开始递推求出每辆车的最终位置。复杂度为O(nlogC),也可以过。
UPD 发现有很多大佬写了O(n)的做法,大概是这样:最终通过停止线的时候,一定是一个车后面堵着剩余所有的车,那么影响时间的就只有最前面这辆车,所以对于每一辆车,假设是它是和0车堵在一起的最靠前的一辆车,那么可以计算出一个值,所有的车的计算值的最大值就是答案。
Path
题意为给定一个有向图,删掉一条边的代价为边权,要求以尽可能少的总代价删掉一些边,使得最短路增加。
先求出最短路,然后保留所有满足dey−dex=ew的边,对于新的图求1到n的最小割即为答案。
Typewriter
对于i从小到大处理,维护使得s[j:i]∈s[1:j−1]的最小的j(s[l:r]表示子串slsl+1...sr),那么记f[i]为输出前i个字符的最小代价,则f[i]=min{f[i−1]+p,f[j−1]+q}。
用SAM维护s[1:j−1],若s[1:j−1]中包含s[j:i+1],即加入第i+1个字符仍然能复制,就不需要做任何处理。否则,重复地将第j个字符加入后缀自动机并j=j+1,相应维护s[j:i+1]在后缀自动机上新的匹配位置,直到s[j,i+1]∈s[1,j−1]。
UPD 出题人的的程序跑了600+ms,验题人的程序跑了900+ms,也并没有特地优化时间……开这个时限本意就是卡掉非线性的做法,但是目测误伤了很多写线性做法的大佬,非常抱歉!
Meteor
题意为求分子分母均小于等于某个值n的第k大的最简分数。
首先考虑二分一个值k,求出小于这个值的分子分母≤n的最简分数个数,即为:
==i=1∑nj=1∑⌊ki⌋[(i,j)=1]i=1∑nj=1∑⌊ki⌋d∣i,d∣j∑μ(d)d∑μ(d)i=1∑⌊dn⌋⌊ki⌋
二分的时候写分数二分,二分O(logn)次就可以收敛到仅包含一个符合条件的分数的区间。最后在Stern-Brocot Tree上遍历,求出≥左端点l且满足条件的最小的符合条件的分数即为答案。
在分数二分之后,k变成ba的形式,因此后半和式就可以用类欧几里得来算。
二分的部分复杂度为O(nlognlogC)(C代表二分出的分子分母的值),然后在树上遍历求答案的复杂度为O(n)(在所求答案为n1时可以取到上界)。
Desert
对于一个有根仙人掌,去掉根之后的每个连通块都会是许多有根仙人掌串起来的一个“序列”,且互为对称的两个序列被认为相同。例如:
[外链图片转存失败(img-rckZimCt-1563840303961)(.so.png)]
从这个角度考虑,令an表示n个点的有根仙人掌数目,bn表示n个点的“仙人掌序列(互为对称的两个序列视为不同)”的个数,cn 表示共有 n 个点并由奇数个仙人掌组成的“回文仙人掌序列”的个数,dn表示共有n个点的“仙人掌序列(互为对称的仙人掌序列视为相同)”的个数,则b,c,d 的求法容易得到:
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧bncndn=an+i=1∑n−1aibn−i=an+i=1∑⌊n/2⌋aicn−2i=21(bn+cn+[2∣n]bn/2)
而按照前面的分析,an就是由n−1个点组成若干个“仙人掌序列(互为对称的仙人掌序列视为相同)”的方案数。因此
n∑anxn=xi=1∏∞j=1∏dik=0∑∞xik
枚举 (i,j) 表示枚举一种序列,k 表示这种序列的个数。等式右边的乘积展开之后每项即为若干个 xik 的乘积,表示某种 i 个点的仙人掌序列选了 k 个。
对这个等式进行处理:
n∑anxn⇔n∑anxn−1⇔lnn∑anxn−1⇔dxdlnn∑anxn−1⇔n>1∑(n−1)anxn−2⇔n>1∑(n−1)anxn⇔n>1∑(n−1)anxn=xi=1∏∞j=1∏dik=0∑∞xik=i=1∏∞(1−xi)di1=i=1∑∞ln(1−xi)di1=i=1∑∞dij=1∑∞jxij=i=1∑∞idij=1∑∞xij−1=(n∑anxn−1)(i=1∑∞idij=1∑∞xij−1)=(n∑anxn)(i=1∑∞idij=1∑∞xij)=(n∑anxn)⎝⎛i=1∑∞xij∣i∑jdj⎠⎞
令左右两边对应项系数相等即可以得到an 的递推式:
an=[n=1]+[n>1]n−11i=1∑n−1⎝⎛j∣i∑jdj⎠⎞an−i
分治FFT求出a,b,c,d即可。
String
一位位地构造答案字符串,每次贪心地加能加入的最小的字符(判断能否加入只要判断加入之后原字符串剩下的后缀中的每种字符的数目能否足够满足条件)。
Kingdom
记前序序列为a[],中序序列为b[]。首先考虑到,如果一个数既没有在a[]中出现也没有在b[]中出现,那么说明当所有出现过的数确定之后,它放在任何一个位置上都可以。
再来考虑出现过的数,显然如果树的形态确定了,那么这些数的位置一定确定了。定义 f[x][l][r] 为 a[x]做根,对应的子树为 b[]中的 [l,r] 区间,有多少不同的树的形态。如果一个数仅在 a[] 或 b[] 中出现过,那么它可以和 0 对应。否则,需要把它在两个序列中的位置对应。在区间 DP 划分区间的时候考虑这些数出现的合法性再转移即可。
最后,假如有 k 个数既没有出现在 a[]中也没有出现在b[]中,那么答案即为 f[1][1][n]⋅k!
另外,对于每个状态(x,l,r),可以推得这种状态中有多少个对位置可以随意确定,那么可以在转移的过程中乘一个组合数,相当于把空位可以填的数字分给两个子区间,这样可以直接求出最终的答案。
由于非法状态比较多,写记忆化搜索跑的比较快。
Function
=i=1∑ngcd(⌊3i⌋,i)a=1∑⌊3n⌋i=1∑ngcd(a,i)[⌊3i⌋=a]
又有
⌊3i⌋=a⇔a≤3i<a+1⇔a3≤i≤(a+1)3−1
因此
=i=1∑ngcd(a,i)[⌊3i⌋=a]i=a3∑min{n,(a+1)3−1}gcd(a,i)
设r=⌊3n⌋−1,则带回原式子
=i=1∑ngcd(⌊3i⌋,i)i=⌊3n⌋3∑ngcd(⌊3n⌋,i)+a=1∑ri=a∑(a+1)3−1gcd(a,i)
而
===i=1∑ngcd(a,i)d∑di=1∑n[gcd(a,i)=d]d∑dt∣di,t∣da∑μ(t)T∣a∑⌊Tn⌋d∣T∑dμ(dT)
注意∑d∣Tdμ(dT)=φ(T),则O(3n)预处理φ(T)之后,答案式子中的第一个和式可以O(6n)地计算出来。
第二个和式可以化为
=a=1∑rT∣a∑(⌊T(a+1)3−1⌋−⌊Ta3−1⌋)φ(T)T∑φ(T)b=1∑⌊Tr⌋(⌊T(bT+1)3−1⌋−⌊T(bT)3−1⌋)
而
==⌊T(bT+1)3−1⌋−⌊T(bT)3−1⌋⌊b3T2+3b2T+3b⌋−⌊b3T2−T1⌋3Tb2+3b+1
因此
=a=1∑ri=a∑(a+1)3−1gcd(a,i)T=1∑rφ(T)[(3Tb=1∑⌊Tr⌋b2)+(3b=1∑⌊Tr⌋b)+⌊Tr⌋]
可以O(3n)求出。
总复杂度O(T3n)。
n比较小的情况可能会出问题,注意要适当特判。也有其它的算法,只要是线性应该都是能过的。把3n出到107是为了卡非线性做法。
Sequence
令bi=∑j=i−k⋅xaj(0≤x,1≤j≤i),则∑bixi=(∑aixi)(∑xik),因此操作的顺序没有影响,可以统计各类操作次数,然后批量处理,也就是∑xik的幂。
由于n,m比较大,直接做快速幂或者ln+exp大概会T,但是(∑xik)n=∑(in−1+i)xik,因此可以省掉求幂,对于一种操作只做一次卷积即可。
Code
d=2时,f(x)=sign(wT⋅x)=w0+w1x1+w2x2,f(x)=0对应于二维平面上的一条直线,直线一侧的点取值为 1,直线另一侧的取值为 −1。故该问题等价于能否找到一条直线将平面上的两类点分开,等价于判断这两类点分别组成的两个凸包是否相交。