嘿嘿,偷学一波!
由于博主做的题比较少,所以没按年份整理,直接按照做题时间放上来了。
2020年9月20日
[POI2013]LUK-Triumphal arch
给你一颗\(n\)个点的树(\(n\leq300000\)),1号节点已被染黑,其余是白的,两人轮流操作,一开始B在1号节点,A选择\(k\)个点染黑,然后B走一步,如果某一时刻B能走到A没染的节点则B胜,否则当A染完全部的点时,A胜。求能让A获胜的最小的\(k\)。
比较容易想到的错解是计算每一个点及祖先的出度作为染色总数。
但这样做忽略了一个事实:A的决策会影响B的决策。B每次一定是朝着对A最为不利的方向移动的。
正确的方法是二分\(k\)的大小,然后自下而上统计出到每个点之前需要染掉这个子树内的多少个点才能来的及抢在B抵达任意一个点之前将那个点染黑,这样如果到1之前需要染掉的节点个数超过1的话,即可判定k过小。
[POI2015]KUR
给定\(n,a,b,p(2\leq n\leq10^9,1\leq p,a,b,m<n,1\leq m\leq10^6)\),其中\(n,a\)互质。定义一个长度为\(n\)的01串\(c[0..n-1]\),其中\(c[i]=0\)当且仅当\((ai+b)\bmod n < p\)。给定一个长为\(m\)的小01串,求出小串在大串中出现了几次。
差一点想出来。
本来的思路是枚举一开始那个位置的数,然后利用小01串构建\(m\) 个约束条件,然后在利用\(\operatorname{Exgcd}\)暴力算出每个数在序列中的出现次数,然而数的个数依然可能很多。
原因在于我忽略了\(n,a\)互质的条件。
\operatorname{lcm}(n,a)=n\times a
\]
所以在前\(n\)项中\(a\times i\)在模\(n\)意义下互不相同。
所以这\(m\)个条件的交集就是答案。
具体来说,设开始位置为\(s\),对于第\(i\)个约束条件(假设小串中\(s_{i}=0\),若\(s_{i}=1\)则条件相反),需要满足:
a\times s+a\times i+b< p\pmod n
\]
不难发现,对于任意一个约束,符合条件的\(a\times s\)一定是条线段,最后对线段求交,但是对线段求交较难实现,所以我们利用正难则反的思想转化为对线段的补集求并即可。
转化为补集后的条件:
0\leq a\times s+a\times i+b\leq p-1(s_{i}=1)
\]
2020年9月21日
[POI2012]ODL-Distance
给你一个序列\(a\)(长度为\(10^5\),值域为\(10^5\)),定义\(\operatorname{d}(i,j)\)为每次操作对\(a_{i},a_{j}\)其中之一乘一个质数\(p\)或除以一个质数\(p\)(\(p\)必须为被除数的约数),让\(a_{i}=a_{j}\)的最少操作步数。
对于每个\(i\),求\(\operatorname{d}(i,j)\)最小的\(j\),若有多个解,输出最小的\(j\)。
题意转化后即是对于每个数找出一个数,使得这两者除掉\(\gcd\)之后质因子系数之和最小.
由于值域不大,我一开始考虑暴力分解质因数之后通过枚举质因数的系数,但是这样时间复杂度无法从\(n^2\)降下来。
根据题解的思路,我们考虑到每个答案都对应着一个\(\gcd\),我们枚举这个\(\gcd\),这样我们可以求出每个数的所有可能答案以及一些一定不会是最优的多余答案,取最大的答案即可.
由于枚举倍数的时间复杂度为调和级数,所以时间复杂度为 \(\Omicron(n\log n)\)。
2020年9月27日
[POI2008]BBB-BBB
一个长度为\(n\)的记账单,\(+\)表示存\(¥1\),\(-\)表示取\(¥1\)。现在发现记账单有问题。一开始本来已经存了\(¥p\),并且知道最后账户上还有\(¥q\)。
你要把记账单修改正确,使得 :
1:账户永远不会出现负数;
2:最后账户上还有\(¥q\)。
你有2种操作:
1:对某一位取反,耗时\(x\);
2:把最后一位移到第一位,耗时\(y\)。
求最小耗时。
一开始还在思考操作1,2的综合贪心策略,但是发现好像可以暴力枚举执行了几次2操作。
问题在于如何判断要执行几次1操作。
贪心的想,肯定从前往后执行1操作。
刚刚由于不熟悉黑BZ不小心看到了题解的标签(单调栈),但是并没有头绪,不过想到了一种基于线段树的暴力方法,即暴力维护前缀和。仔细一想发现可以不用线段树,可以用优先队列来进行维护。
2020年9月28日
[POI2006]EST-Aesthetic Text
输入\(M,N\),代表文章的某一行的总长度不能超过\(M\)。\(N\)代表有\(N\)个单词 第二行给出\(N\)个数,代表这\(N\)个单词各自的长度。你的任务就是进行文章排版操作.使文章的不和谐度最小。相邻两行见的不和谐度为这两行的长度的差的绝对值。如果文章只有一行的话,则不和谐度为0.你可以将多个连续的单词放到同一行去,任两个单词间用一个空格格开,但这一行的总长度不能超过\(M\)。 \(1<=M<=10^6,1<=N<=2000,1<=Ai<=M\)。
\(dp_{i,j}\)表示当前句子中最后一个单词为第\(i\)个单词,前一句话的最后一个单词是\(j\)。
可以转化题意,把空格算入每个单词中,给每个单词长度加1,两行长度之差不变。
转移方程:
令\(F(i,j)=S_{i}-S_{j}\times2\).
\(dp_{i,j}=min\lbrace dp_{j,k}+|F(i,j)+S_{k}|\rbrace\).
转移的过程中可以用前缀和优化,对于每个状态\(dp_{j}\)的所有合法状态\(dp_{j,k}\),我们按照\(S_{k}\)排序,分别预处理\(dp_{j,k}+S_{k}\)和\(dp_{j,k}-S_{k}\)的前后缀最小值。然后枚举所有合法后继状态\(dp_{i,j}\),转移时二分绝对值函数拐点并分类讨论即可。
2020年10月6日
咕咕咕~
2020年10月7日
咕咕咕~
2020年 10月16日
咕咕咕~
2020年10月17日
[POI2011]LIZ-Lollipop
给一个长度为\(n\)的由1和2构成的序列,\(m\)次询问,每次询问有没有一个子串的和为\(k\)。
\(1\leq n,m\leq10^6,1\leq k\leq2\times10^6\).
一道很好的思维题,可惜被我乱搞过掉了。。。
首先可以将原序列转化,将所有的2展开成2个1。
此时题意转化为:给你一个序列,有一些位置不能作为开头,有一些位置不能作为结尾,问你是否能选出一个长度为\(k\)的子串。
我们深入分析,发现这个新序列有着以下性质:
- 对于任意一个不能作为结尾的位置,它的后一位一定可以作为结尾。
- 对于任意一个不能作为开头的位置,它的前一位一定不能作为结尾。
- 序列最后一个位置一定可以作为结尾。
总结以上两条性质可以得出:
- 对于任意两个不能/可以(状态相同)作为结尾的位置,他们一定对应了一个合法的子串。
- 对于一个询问\(k\),如果无解,那么每一对距离为\(k\)的位置一定恰好一个可以作为结尾,一个不能作为结尾。
那么我们可以对整个序列进行染色,黑色表示这个位置可以作为结尾,白色表示这个位置不能作为结尾。
然后我们发现,整个序列一定会被划分成长度为\(k\)(除最后一段)的若干块,相邻两块中同一位置的所有颜色必定相反。
那么我们可以预处理出这个新序列的哈希值和将颜色反转之后的哈希值,这样就可以快速判定相邻两块中是否存在合法的子串。
至于如何定位这个子串的左端点,只需要在块内二分即可。
同时注意到对于每一个k我们都可以只做一次,这样的话时间复杂度为\(\Omicron(n\times(\frac{1}{1}+\frac{1}{2}+…+\frac{1}{n}))=\Omicron(n\log n)\),而定位每个串的端点时间复杂度为\(\Omicron(m\log n)\),所以总时间复杂度为\(\Omicron((n+m)\log n)\),可以通过本题。
注意:这道题在loj上时限非常小,必须使用单哈希才能通过。