POI2015 合集

KUR

题面

考虑小串会在大串的哪些位置出现,然后就是设小串开头的位置为 \(x\),然后小串第 \(i\) 个位置如果 \(a_i=0\) ,则 \(0\leq a(x+i)+b<p (\mod n)\)\(a_i=1\) 同理,然后用这个关系解出 \(ax\) 的取值范围。但注意 \(x\) 取不到 \([n-m+1,n]\) ,因为这样小串放不下,所以暴力的删掉就行了。

PIE

题面

就每次从最上面中最左面开始验证就行。如果每次把整个矩阵扫一遍复杂度是错的,但每次只验证 \(x\) 的位置就是对的因为这样每个 \(x\) 只会被验证一次。

就我这种垃圾才会调这么久的 QAQ

KIN

题面

对于每个右端点,找一个最优的左端点。所以从左往右扫,每次扫到一个颜色就把从这个位置到这个颜色上一次出现的位置加上贡献,其余位置减掉贡献,然后找区间最大值。

MOD

题面

跟 JD1024 删边是一样的题,就是麻烦了点,最长链就是把删掉的直径拼在一起,最短的就是把两个直径的中点连在一起。需要注意的是最短的如果直径中点连起来比某一个直径小,这个新连起来的东西就无法成为最小值,计算的时候应该用最长的直径计算

WYC

题面

倍增 floyd 的奇妙应用!

边权是 1,2,3 就可以拆点了。拆点的话不怎么难。倍增 floyd 就是处理跳 \(k\) 步的,矩阵里存的是方案数,我们可以提前预处理出跳 \(2^k\) 步的方案数,但是方案数只计算主点的,计算方法就是用一个临时矩阵,从 \(0\)\(i\) 各连一条边,原矩阵一开始要从 \(i\)\(0\) 连一条边,这样主点和 \(0\) 可以形成回路, \((0,0)\) 的值就是答案。

预处理之后就只需要用倍增之类的办法让他跳之后的步数正好小于 \(k\) ,(因为倍增的一个性质就是可以拆分成二进制数嘛)。

需要注意的是不是 \(0\) 的点的含义是走过了这一步的方案数,\(0\) 的含义是还未走过这一步的方案数

MYJ

题面

这道题的比较人类智慧的状态定义。就是设 \(f_{i,j,k}\) 表示从第 \(i\) 家到第 \(j\) 家,最小值为 \(k\) 的最大收益的和。然后要枚举也是分割点,还要找到对于所有属于 \([i,j]\) 的区间中,每个点被多少区间越过去了。

然后转移就是这样的 \(f_{i,j,k}=\max \{f_{i,l-1,k}+f_{l+1,j,k}+cnt_{l,k}\times k\}\) ,其中 \(cnt_{l,k}\) 表示经过 \(l\)\(c\) 大于等于 \(k\) 的区间个数。然后发现 \(k\) 不重要,只关心他和 \(c\) 之间的关系,所以离散化一下,复杂度 \(O(n^3 m)\) 的。

ODW

题面

看到隔几步跳一次的就应该想到根号分治。如果跳的步数大于 B,就直接转移,否则就是维护每个点向上跳的步数为 \(k\) 的前缀和,然后直接找到到哪里开始减就行了。

我感觉ynoi 那个比这个别扭一些

TRZ

题面

一开始照着题解写了个假东西。

考虑枚举 \(l\) ,那么一定是从 \(r\) 开始删字符,然后删到合法为止。考虑最远的 \(r\) 一定是 \(n\) ,然后就是如果此时三个字符数量相同,那么就往前推一位,然后就变成了两种字符相同,剩下一种不同。这时候又有不同情况。肯定是要删掉那些不同字符的一个了,那么如果再删一个导致和另外那个相同就又不行了。或者是另外那种比相同的两种多一个,这样再跳一步就还可能导致相同。

那么现在有两种情况解决不了,分别是数量为 \(x,x,x+1\)\(x,x,x-1\)。这时候我们考虑 dp。

\(f_{i,j,k}\) 表示到第 \(i\) 位,那个不一样的字符为 \(j\) ,那个字符的数量是多 1 还是少 1,之后会跳到的位置。

\(a_i=j\) 时,\(f_{i,j,0}=f_{i-2,a_{i-1},0},f_{i,j,1}=lst_{i}-1\)\(lst\) 表示在 \(i\) 前面第一个不是 \(a_i\) 的位置。

\(a_i\not =j\) 时,\(f_{i,j,1}=i-1,f_{i,j,1}=f_{i-1,g(s_i,j),0}\)\(g_{i,j}\) 表示既不是 \(i\) 也不是 \(j\) 的字符。

然后求出 \(f\) 就可以直接用 \(f\) 模拟就行了。

PUS

题面

假设 \(k,n\) 都比较小,那么就可以暴力连边。就是差分约束那种想法,某个点的最长路就是最小可能取值,如果最小取值大于给定的值就不行。如果成环了也不行。

然后这道题就是线段树优化建图,就是把所有关键点都连到一个辅助点上,然后辅助点连到线段树各个节点上,然后再做差分约束就行了。

我做的时候连的负边权。就是算最短路,得到的是可能的最大值,然后就是和 0 和给定的值作比较就行了,初值就都赋成 1e9就行了。

LAS

题面

考虑人的话太烦了,所以正难则反!考虑人不行就考虑食物呗。

\(f_{i,j}\) 为第 \(i\) 种食物,\(j\) 种状态能不能选。\(j\) 就是四种,分别是不吃,左边的人吃,右边的人吃。然后先钦定 1 的状态,然后转移到 \(n\) 之后再转移回 1 ,看能不能回到钦定的状态。不能就是回不到。能的话就用 \(f\) 推测出人的状态。

转移啥的就硬分类讨论就完事了。嗯。就看代码就行了,懒得抄了。

CZA

对于 \(p=0\) 的情况只有 \(n=1\) 时是可行的,其余都是一定不行的。

对于 \(p=1\) 的情况 \(n>2\) 时一定不行,\(n=2\) 需要看是否有冲突。

对于 \(p=2\) 的情况只需要往 \(n\) 个位置填数就行,最多两种情况。

然后 \(p=3\) 的情况就是很复杂的了。

我们可以考虑按顺序一个一个从大到小插入元素。那么能对 \(i\) 产生影响的只有 \(i+1,i+2,i+3\),它们三个之间的顺序会对答案有影响,它们之间如果有其他的数字也是插不进去的。

所以我们设状态 \(f_{i,j,k}\) 表示将要插入第 \(i\) 个数,第 \(i\) 个数的前三个数是顺时针还是逆时针排列的,它们三个之间有没有其他的数字。

然后我也不知道说啥了。

就硬转移就行了呗。

需要注意的是当前 \(i\) 转移完之后,\(i+3\) 一定需要左右两侧都处在合法的状态,但是 \(i+1,i+2\) 不需要,因为他们旁边可能将来会插入更小的数字让它们合法。

		if(ok(i+2,i)&&ok(i,i+3)) g[0][6]+=f[ii][0][5],g[0][6]%=mod;
		if(ok(i+3,i)&&ok(i,i+1)) g[0][3]+=f[ii][0][6],g[0][3]%=mod;
		if(ok(i+1,i)&&ok(i,i+2)) g[1][2]+=f[ii][0][3],g[1][2]%=mod;
		if(checkx(i,0,5)&&ok(i+3,i)&&ok(i,i+1)) g[0][3]+=f[ii][0][4],g[0][3]%=mod;
		if(checkx(i,0,6)&&ok(i+2,i)&&ok(i,i+3)) g[0][6]+=f[ii][0][4],g[0][6]%=mod;
		if(checkx(i,0,3)&&ok(i+3,i)&&ok(i,i+1)) g[0][1]+=f[ii][0][2],g[0][1]%=mod;
		if(checkx(i,0,6)&&ok(i+1,i)&&ok(i,i+2)) g[1][2]+=f[ii][0][2],g[1][2]%=mod;
		if(checkx(i,0,5)&&ok(i+1,i)&&ok(i,i+2)) g[1][2]+=f[ii][0][1],g[1][2]%=mod;
		if(checkx(i,0,3)&&ok(i+2,i)&&ok(i,i+3)) g[0][4]+=f[ii][0][1],g[0][4]%=mod;
		if(checkx(i,0,4)&&ok(i+1,i)&&ok(i,i+2)) g[1][2]+=f[ii][0][0],g[1][2]%=mod;
		if(checkx(i,0,2)&&ok(i+2,i)&&ok(i,i+3)) g[0][4]+=f[ii][0][0],g[0][4]%=mod;
		if(checkx(i,0,1)&&ok(i+3,i)&&ok(i,i+1)) g[0][1]+=f[ii][0][0],g[0][1]%=mod;
		if(ok(i+1,i)&&ok(i,i+3)) g[1][3]+=f[ii][1][6],g[1][3]%=mod;
		if(ok(i+3,i)&&ok(i,i+2)) g[1][6]+=f[ii][1][5],g[1][6]%=mod;
		if(ok(i+2,i)&&ok(i,i+1)) g[0][2]+=f[ii][1][3],g[0][2]%=mod;
		if(checkx(i,1,6)&&ok(i+3,i)&&ok(i,i+2)) g[1][6]+=f[ii][1][4],g[1][6]%=mod;
		if(checkx(i,1,5)&&ok(i+1,i)&&ok(i,i+3)) g[1][3]+=f[ii][1][4],g[1][3]%=mod;
		if(checkx(i,1,6)&&ok(i+2,i)&&ok(i,i+1)) g[0][2]+=f[ii][1][2],g[0][2]%=mod;
		if(checkx(i,1,3)&&ok(i+1,i)&&ok(i,i+3)) g[1][1]+=f[ii][1][2],g[1][1]%=mod;
		if(checkx(i,1,5)&&ok(i+2,i)&&ok(i,i+1)) g[0][2]+=f[ii][1][1],g[0][2]%=mod;
		if(checkx(i,1,3)&&ok(i+3,i)&&ok(i,i+2)) g[1][4]+=f[ii][1][1],g[1][4]%=mod;
		if(checkx(i,1,1)&&ok(i+1,i)&&ok(i,i+3)) g[1][1]+=f[ii][1][0],g[1][1]%=mod;
		if(checkx(i,1,2)&&ok(i+3,i)&&ok(i,i+2)) g[1][4]+=f[ii][1][0],g[1][4]%=mod;
		if(checkx(i,1,4)&&ok(i+2,i)&&ok(i,i+1)) g[0][2]+=f[ii][1][0],g[0][2]%=mod;

我知道我写丑了,但是因为写完之后就除了判断 \(i+3\) 合法那块整体有问题,细节上没有错,所以我就没改成循环位运算合并的形式

然后因为写丑了,所以需要用滚动数组

posted @ 2022-10-02 10:08  cc0000  阅读(68)  评论(0编辑  收藏  举报