POI2012
POI 2012
Festival
有 \(n\) 个正整数,\(m_1+m_2\) 个限制条件,条件分为两类:
- 有 \(m_1\) 个条件给出 \(a,b\) ,要求满足 \(x_a+1=a_b\)
- 有 \(m_2\) 个条件给出 \(c,d\) ,要求满足 \(x_c\leq x_d\)
求在满足所有限制的情况下,\(x_{1...n}\) 最多有多少个不同的值?
\(2\leq n\leq 600,m_1+m_2\leq 10^5\)
可巧的是在做这题之前我正好在学差分约束,然后打开 POI 的第一道题就是这个。(然后我决定推销一下这个)
然后很容易建出来差分约束系统,然后你发现你还是不会求(((
但是如果是一个强连通图的话是会做的,只需要求出任意两点间的最大差值(也就是建出图之后求最短路),然后取最大值 +1 就是。因为你在强连通分量里面走的时候每一步都是要么只 +1 ,要么只 -1 ,每一个数都是紧挨着上一个数的,所以最大的差值里面所有数字都能取得到,所以只需要再加 1 就是这个强连通分量里的答案。
那我们就可以先缩点,对每个强连通分量都求出来答案,然后可以发现的是,建图的时候有边权的边一定是双向边,也就是说连接各个强连通分量的边一定是边权为 0,那么就是两个强连通分量之间互不影响,就是说你可以把两个强连通分量之间的差距拉得很大很大,,然后就互不影响了,于是答案就是所有强连通分量能贡献的答案之和。
求最短路我用的 floyd ,无解就是有负环的情况,floyd 判负环就是判 \(dis[i][i]\) 是否小于 0 ,小于 0 就是有负环。
Letters
给出两个长度相同的的只含大写字母的字符串 \(a, b\),每次可以交换 \(a\) 中相邻两个字符,求最少的交换次数,使得 \(a\) 交换后的得到的字符串与 \(b\) 相同。
\(n\leq 10^6\) ,保证 \(a,b\) 中只有大写字母且保证 \(a\) 一定可以变成 \(b\)
重新标号,求一下逆序对就完事了
Distance
对于两个正整数 \(a,b\),这样定义函数 \(d(a,b)\):
每次操作可以选择一个质数 \(p\),将 \(a\) 变成 \(a\times p\) 或 \(\frac a p\),如果选择变成 \(\dfrac{a}{p}\) 就要保证 \(p\) 是 \(a\) 的约数,\(d(a,b)\) 表示将 \(a\) 变成 \(b\) 所需的最少操作次数。
现在给出 \(n\) 个正整数 \(a_{1\dots n}\),对于每个 \(a_i\),求最小的 \(j\) 使得 \(i\not =j\) 且 \(d(a_i,a_j)\) 最小。
\(n\leq 10^5,a_i\leq 10^6\)
首先,一个数转化成另外一个数的代价和两个数都转化为 \(gcd\) 的代价,与两个数都变成 \(1\) 的代价再减掉 \(gcd\) 变成 \(1\) 的代价的二倍。而一个数变成 \(1\) 的代价就是这个数所有质因子的指数的和。这个指数的和可以用线性筛轻松地筛出来。我们设对于 \(i\) 变成 \(1\) 的代价为 \(f_i\) 。
然就是我们要对于每一个 \(f_i\) 都要求最小的 \(f_{a_i}+f_{a_j}-2\times f_{gcd(a_i,a_j)}\) ,直接枚举 \(j\) 是 \(n^2\) 的,对于这样三元的东西,不都是先枚举两个再求第三个,那枚举 \(i,j\) 会炸,我们就可以枚举 \(gcd\) ,即 \(a_i\) 的约数,然后用这两项寻找最优的 \(j\)。我们可以先预处理出每个数的倍数中最小的 \(f_{a_i}\) ,这样就能直接找到最优的 \(f_{a_j}\) 了,但是这样可能找到 \(i\) 自己,所以还要维护一个次小值
然后你可能会问这样求出的 \(a_i,a_j\) 的 \(gcd\) 不一定是那个枚举的东西,不过不过没关系,因为真正的 \(gcd\) 一定会被枚举到,所以没有情况会被忽略。
预处理最小值是 \(n\sqrt n\) 的,枚举约束也是 \(n\sqrt n\) 的。
Rendezvous
一个 \(n\) 个点的有向图,每个顶点有且仅有一条出边。然后给出 \(q\) 组询问,每组询问给出 \(a\) ,\(b\) ,求 \(x,y\) 使得 \(a\) 沿着出边走 \(x\) 步和 \(b\) 沿着出边走 \(y\) 步到达的顶点相同。
如有多解,输出 \(\max\{x,y\}\) 最小的一种,如还有多解,输出 \(\min\{x,y\}\) 最小的一种,如还有多解,输出 \(x\geq y\) 的那种。
如不存在这样的 \(x,y\) ,请输出 -1 -1
\(n,q\leq 5\times10^5\)
这是个基环树能看得出来吧 QAQ
考虑把所有在环上的节点当作根。对于一组询问,有这样几种情况:
- \(a,b\) 不在同一个联通块里,一定不存在解。
- \(a,b\) 的根相同,那就是 \(lca\)
- \(a,b\) 的根不相同,就一定是先各自跳到根上,然后要么从 \(a\) 的根走到 \(b\) 的根,要么从 \(b\) 的根走到 \(a\) 的根(这样一定是最优的)
然后判断环我用的是拓扑排序,拓扑排序结束之后如果存在入度不为 \(0\) 的点,就说明它在环上。
Well
给出 \(n\) 个正整数,每次可以进行不超过 \(m\) 次操作,每次操作选择一个非 0 数,并将它减一,要求最终有一个数是 \(0\) ,求最小的 \(z=\max\{|x_i - x_{i-1}|\}\) 最小
\(n\leq 10^6,m\leq 10^{18},1\leq x_i\leq 10^9\)
保证方案一定存在
首先容易想到二分答案,然后验证是否可行。对于当前二分到的 \(mid\) ,我们先不考虑把一个数变成 0 ,就是满足后面的条件,方法就是先从左到右扫一下,使 \(x_i-x_{i-1}>mid\) 的 \(x_i\) 符合条件。然后从右向左扫,使 \(x_i-x_{i+1}>mid\) 的 \(x_i\) 符合条件。然后就考虑怎么把一个数删成 \(0\) ,枚举被删成 \(0\) 的数的过程中,受影响的数的左右端点一定是单调不减且互不影响的。然后我们就可以用类似滑动窗口的东西维护左右端点。然后如果找到最靠前的符合条件的数就行了。
Vouchers
对于正整数集合,有 \(n\) 组人依次来取数,第 \(i\) 组来了 \(x_i\) 个人,他们取的数都一定是 \(x_i\) 的倍数,并且是剩下的数的最小的 \(x_i\) 个。
集合中有 \(m\) 个数,分别为 \(k_i\) ,被标记成为“幸运数”,问都有谁取到了幸运数
\(1\leq n,m,x_i,k_i\leq 10^6\)
如果是暴力的话,做法就是依次枚举向后找合法的数就行了。那我们可以记录一个 \(f_x\) 表示上一次 \(x_i=x\) 的那组取到的最后一个数是什么。然后下一次从 \(f_{x_i}+x\) 开始枚举。
然后还有一个更重要的优化就是如果枚举的位置已经超出了最大的幸运数了,就不用继续枚举了,因为这样是无用的。
至于怎样分析复杂度,因为至多有 \(n\) 中不同的 \(x\) ,而枚举的上界是 \(k_i\),所以复杂度是 \(\sum \frac k i\) ,因为 \(k\) 与 \(n\) 同级,所以复杂度就是 \(O(n\ln n)\)
Cloakroom
有n件物品,每件物品有三个属性\(a[i], b[i], c[i] (a[i]<b[i])\)。
再给出q个询问,每个询问由非负整数 \(m, k, s\) 组成,问是否能够选出某些物品使得:
- 对于每个选的物品i,满足\(a[i]<=m\) 且\(b[i]>m+s\)。
- 所有选出物品的 \(c[i]\) 的和正好是 \(k\)。
\(n,c_i\leq 1000,a_i,b_i,m,s\leq 10^9 ,k\leq 10^5\)
对于每个物品,我们可以把它看作是 \([a_i,b_i]\) 的一条线段,对于每个询问都看作是 \([m,m+s+1]\) 的一条线段,那么就是求能完全覆盖当前区间的区间中,能不能让 \(c\) 的和为 \(k\).
所以我们把询问离线下来,然后把物品和询问的区间都按照左端点排序,然后做一个背包。背包维护的东西是 权值和为 k 的所有选法中,最小的右端点的最大值是什么。\(f_k=\max\{\min\{f_{k-c_i},b_i\},f_k\}\),在枚举当前询问的时候,把所有左端点小于当前询问的左端点的物品都用背包转移一下,然后看 \(f_{k_i}\) 是否大于右端点,如果大于就是可以,否则是不行的。
Squarks
有 \(n\) 个互不相同的正整数,任取两个 \(x_i,x_j(i\not = j )\) ,能算出 \(x_i,x_j\)
现在给你所有取法的 \(\frac {n(n-1)}{2}\) 个数,请你求出 \(x_{1\dots n}\),要求输出所有方案,输出的 \(x_i\) 要求递增,
\(n\leq 300,x_i\leq 10^8\)
首先我们从小到大排序,最下的那个和一定是 \(x_1+x_2\),次小的那个一定是 \(x_1+x_3\) ,然后次次小的可能是 \(x_1+x_4\) ,\(x_1+x_5\dots\),也可能是 \(x_2+x_3\)
所以我们没办法确定谁是 \(x_2+x_3\) ,所以我们可以枚举谁是 \(x_2+x_3\)。这样我们就求出了前三个数,这样,剩下的最小值一定是 \(x_1+x_4\),然后 \(x_4\) 就能求出来,然后去掉 \(x_1+x_4,x_2+x_4,x_3+x_4\) 之后,最小的数就是 \(x_1+x_5\) ,然后以此类推,整个序列就能求出来了。
我用了 multiset 维护的还剩下那些数,复杂度 \(O(n^3\log n)\)
Bidding
A 和 B 两个人在玩一个游戏,这个游戏是他们轮流操作一对整数 \((x,y)\)。
初始时 \((x,y)=(1,0)\),可以进行三种操作:
- 将 \((x,y)\) 变成 \((1,x+y)\)。
- 将 \((x,y)\) 变成 \((2x,y)\)。
- 将 \((x,y)\) 变成 \((3x,y)\)。
给定正整数 \(n\)。在 \(x+y\ge n\) 时就不能进行后两种操作。如果某个人操作后 \(y\ge n\),他就输掉了。
保证给出的 \(n\) 为先手必胜的,你需要提供一种先手必胜的方案。例如 \(n = 3\) 时,先手选择操作 3,后手只能选择操作 1 然后输,所以 \(n = 3\) 时先手必胜。
交互题,你需要实现一个函数 extern "C" int _opt(int n, int x, int y),该函数的返回值是一个值为 \(1\),\(2\) 或 \(3\) 的整数,表示现在数对是 \((x, y)\),参数是 \(n\) 且轮到你操作时,你会选择的操作。
\(n\leq 3\times 10^3\)
考虑 dp(这种方程好像在博弈的题里总出现)设 \(f_{i,j}\) 为 \(x=i,y=j\) 的时候当前的人能否赢,能赢的话会怎么走?然后就是当 \(i+j\geq n\) 的时候必败,转移的时候就判断一下就行了。
。
方程要不要写一下
\(f_{i,j}=\begin{cases}-1\text{ if }i+j\geq n\\1 \text{ if }f_{1,i+j}==-1\\2\text{ if }f_{i\times 2 ,j}==-1\\3\text{ if }f_{i\times 3 ,j}==-1\end{cases}\)
但是这样一定会 MLE。但是可以发现 ,\(x\) 一定可以表示为 \(2^a\times 3^b\) 的形式。
所以可以换一种状态:\(f_{i,j,k}\) 表示 \(x\) 为 \(2^i\),\(3^j,y=k\) 时当前的人的输赢情况。转移和上面是一样的。
所以就可以预处理出 \(f\) ,然后询问就直接输出就行。
Salaries
给出一棵n个结点的有根树,结点用正整数1~n编号。
每个结点有一个1~n的正整数权值,不同结点的权值不相同,
并且一个结点的权值一定比它父结点的权值大(根结点的权值最大,一定是n)。
现在有些结点的权值是已知的,并且如果一个结点的权值已知,它父结点的权值也一定已知。
问还有哪些结点的权值能够唯一确定。
(\(n\leq 10^6\))
我一开始想了个假掉的东西,然后调不出来,然后证明了它是错的,然后打开了题解
神仙题。
这个题最神仙的思路是先求出每个点最大能取到的数字是什么。对于一个点来说,如果这个点本来是有权值的,那么最大取值就一定是当前权值,否则,它最大能取到的权值就是剩下没有选过的数字中最大的小于它父亲的权值的数。
求出这个最大能取到的权值之后,如果有多个数字的最大取值是相同的,那么这些点都不能唯一确定取值(因为它们都不能确定是否是最大取值),然后就是如果一个点的最大取值是 \(mx\) ,那么所有最大取值小于 \(mx\) 的数字的个数如果小于 \(mx-1\) 就说明前面是有空位的,而后面一定会存在数字不能放到它的最大取值,然后它和当前点可能有一个去到前面的空位上去,所以最大取值小于 \(mx\) 的数如果比 \(mx-1\) 少,就说明当前的点也不能确定是什么。
Warehouse Store
\(n\) 天。第 \(i\) 天上午会进货 \(A_i\) 件商品,中午的时候会有顾客需要购买 \(B_i\) 件商品,可以选择满足顾客的要求,或是无视掉他。
如果要满足顾客的需求,就必须要有足够的库存。问最多能够满足多少个顾客的需求。
我们考虑每次尽可能先满足前面的人,然后把所有已经满足的客人放到大根堆里,然后如果遇到了一个无法满足的客人,就看一下大根堆的堆顶元素是否大于当前的值,如果大于,就弹出堆顶,然后重新计算一下花费。这样做是对的是因为堆顶的元素如果大于当前元素,就说明把堆顶弹出再放进去当前元素一定是可以的,并且还会使花销减少,所以换掉那个一定是在当前情况下更优的。
然后种树那个不也是这种想法吗。
Minimalist Security
一张n个点m条边的无向图,有点权有边权都是非负,且每条边的权值小于等于两个顶点的权值和,现在要将每个点减一个非负整数使得每条边权等于两个顶点的点权和,问最大修改代价和最小修改代价
如果无解输出 NIE
\(n\leq 5\times 10^5,m\leq 3\times 10^6\)
首先设每点要减掉的数值为 \(p_i\) ,然后是 \(val_v-p_v+val_u-p_u=w\) ,移一下项得到 \(val_v+val_u-w=p_u+p_v\) ,设 \(val_u+val_v-w=z\) ,就是 \(z=p_u+p_v\) ,然后把图上的边权改成 \(z\), 我们发现,从一个联通块上任意一点开始走,如果某一个点的 \(p\) 确定了,那么整张图上的 $p $ 都能被唯一确定。
所以我们要求出一个点的 \(p\) ,的取值范围,再求出整个联通块的值的和与这个点的函数关系就行了。假设我们从 \(1\) 这个点开始走,路过的每个点的 \(p\) 都能用形如 \(k p_1+b\) 的形式表示出来。比如对于起始点 \(p_1=p_1+0\) ,假设他和 \(2\) 号点有一条边权为 \(3\) 的点,那么 \(p_2=-p_1+3\) ,然后如果 \(3\) 号点与 \(2\) 号点有一条边权为 \(5\) 的点,那么 \(p_3=p_1+2\) ,以此类推,每个联通块中的点都能被表示出来。但是一个点可能被走多次,求出多个函数关系,那就要对冲突分类讨论了。
假设我们求出了两组关系,分别是 \(k_1,b_1,k_2,b_2\) ,如果 \(k_1\) 和 \(k_2\) 正负性相同,但是 \(b_1\) 和 \(b_2\) 不同,那么这种情况一定不合法,直接输出不行返回,否则不用管他。如果 \(k_1\) 与 \(k_2\) 正负性不同,那么这个时候 \(p_1\) 是可以解出来的。如果此时 \(p_1\) 解出来的不是整数,那就直接无解,如果多次求出来的 \(p_1\) 是不一样的,那么就也是一定无解的。
你把整个联通块的每个点的函数关系都求出来了,因为 \(0\leq p_i\leq val_i\) ,所以对于每个函数关系,都能求出 \(p_1\) 的取值范围,然后如果这个取值范围最后没有交集,最后也是无解,然后如果之前求出过唯一 \(p_1\) ,但是这个取值区间不包含求出的 \(p_1\) ,那么也还是无解。如果最后求出的区间让 \(p_1<0\) 或 \(p_1>val_1\) 也是无解的
最后能求出 \(p_1\in [l,r]\) ,然后求出整个联通块的 \(\sum k\) 和 \(\sum b\) ,最大和最小值都一定是在 \(p_1\) 的极值处取到,然后就根据 \(\sum k\) 的正负性讨论一下什么时候取最大,什么时候取最小就行了。
Prefixuffix
对于两个串S1、S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同。例如串ababba和串abbaab是循环相同的。
给出一个长度为n的串S,求满足下面条件的最大的L:S的L前缀和S的L后缀是循环相同的。
\(n\leq 10^6\)
我们可以先在左右都删掉完全相同的串。然后就是找最长的相同的前后缀。设 \(f_i\) 表示删掉 \(i\) 个字符后的最长能到达的前后缀的长度。有一个易证但是不好想的性质:\(f_{i-1}\leq f_i+2\) ,(自己画一画就好了嘛QAQ)
然后这样就有单调性了,均摊 \(O(n)\) 就能找到 \(f_i\) 了,然后找 \(i+f_i\) 的最大值。
Fibonacci Representation
给你 \(T\) 组询问,每次询问 \(x\) 最少能用多少个斐波那契数相加减表示。
可以重复使用
比如 \(10=5+5,19=21-2,17=13+5-1\)
\(1\leq x\leq 10^{18}\)
由于斐波那契数存在两个 \(1\) ,所以任意正整数都能被表示的。然后由于任意的斐波那契数都能拆成两个斐波那契数,所以我们没必要把一个数拆成两个,所以尽可能地选更大数会更优。所以我们每次二分地找最接近的斐波那契数,然后递归地向下查找。
关于这个贪心的证明,感性理解就是像上面一样。严谨一点的移步题解区吧 QAQ。
Tour de Byteotia
给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上。
\(n\leq 10^6,m \leq 2\times 10^6\)
首先,可以发现删两个端点都大于 \(k\) 的边是没有用的,所以先把它们连上,然后依次加边用并查集判一下环就好了。
至于为啥这样是对的,因为其实本质上是要求一个类似最小生成树的东西。如果生成环了,那断环其实删那条边是无所谓的。
a Horrible Poem
这题有人做了,有人没做,所以做了的请不要大声喧哗
给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节。
如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到。
\(n\leq 5\times 10^5,q\leq 2\times 10^6,\)
如果 \(x\) 是某个子串的循环节,那么 \(x\) 的倍数一定也是循环节。所以我们可以枚举长度的约数,但是这样是 \(n\sqrt n\) 的。所以可以预处理出每个数的最小的质因子是什么,然后每次除以这个最小的质因子,这样每次跳是 \(n\log n\) 的在跳的过程中判断哈希值是否相同。
Leveling Ground
给出n个整数\(X_1,X_2,...X_n\),再给出两个正整数\(a、b\),可以进行下面四种操作:
- 选择正整数\(l,r (1<=l<=r<=n)\),将\(X_l,X_{l+1},...,X_r\)都加上\(a\)。
- 选择正整数\(l,r (1<=l<=r<=n)\),将\(X_l,X_{l+1},...,X_r\)都减去\(a\)。
- 选择正整数\(l,r (1<=l<=r<=n)\),将\(X_l,X_{l+1},...,X_r\)都加上\(b\)。
- 选择正整数\(l,r (1<=l<=r<=n)\),将\(X_l,X_{l+1},...,X_r\)都减去\(b\)。
求最少的操作次数将\({X_i}\)全部变成\(0\)
\(n\leq 10^5,a,b,X\leq 10^9\)
区间操作需要转化成差分数组,然后仍然是要把整个数组变成 \(0\) ,这样操作就是把区间操作转化成了单点修改。然后就是把每个数通过加 \(a\) 减 \(a\) ,加 \(b\) 减 \(b\) 变成 \(0\) 。
我们发现对数进行操作本质上是一个不定方程:\(ax_i+by_i=c_i\) ,\(x_i\) 就是加减 \(a\) 的次数, \(y_i\) 就是加减 \(b\) 的次数。然后就是用裴蜀定理判一下无解(\(c_i \mod gcd(a,b) \not = 0\)时无解) ,然后用扩展欧几里德解出一组特解\((x_1,x_2)\), 通解就是 \(x=x_1+k \frac {b}{gcd(a,b)},y=y_1-k\frac {a}{gcd(a,b)}\) ,因为我们想要代价最小,所以我们就让 \(|x|+|y|\) 最小。先不考虑是否可行,因为 \(x\) 或 \(y\) 一定有一个取到最大负数解或最小正数解,所以每个都判一下就行了。
但是我们这样求出的解是可能不合法的,因为是差分数组上做区间操作,左右的加减要匹配上,所以要求 \(\sum x=0,\sum y=0\) 。当 \(\sum x=0\) 时 \(\sum y\) 也一定等于 \(0\) 。所以我们只考虑 \(x\) 。
当 \(\sum x >0\) 时,我们考虑让 \(x-\frac {b} {gcd(a,b)}\),同时修改 \(y\) ,但是我们不知道怎样操作可以使最终代价最少,所以我们考虑反悔贪心。先把所有如果调整的调整代价放进堆里,每次弹出堆顶,把堆顶元素调整好,然后把新的如果再次调整的代价扔进堆里,重复操作直到 \(\sum x=0\)
现在 \(\sum x=0\) 了,总的代价就是 \(\sum |x_i|+|y_i|\)。

浙公网安备 33010602011771号