[线段树][区间等比/等差数列修改] CodeForces – 446C DZY Loves Fibonacci Numbers

这个题的官方题解简直玄学,根号5取模,然后转化成等比数列,服气。

还好评论区有人给了更简便的做法:广义斐波那契数列。任意两个广义斐波那契数列相加仍然是斐波那契数列,而且只要知道了前两项的和就可以知道任意一项的和和任意一项的开始的前缀和。比如若第一二项为a,b,那么手推几下就可以发现,fab[n]=af[n-2]+bf[n-1],然后前缀和是fsum[n]=f[n+2]-f[2](这个也很容易推出来,甚至奇数项偶数项分别的和都能推出来),然后这时候就很简单了,对于每一个区间只需要保存其左端点处的a,b就可以了,把ab做成lazy tag就可以实现区间修改了。注意这时候pushdown的时候,对于右孩子要计算出来fibab到这个点是多大才可以。一如既往的,add操作需要在maintain里加单节点特判(我也不知道为什么但是已经习惯了)还有一点注意ta一定是+的第一个,tb一定是+的第二个。

准备再用等比数列方法做一遍吧,看看是怎么个操作。。今天写了一下等比数列的操作方法,感觉比原来的方法简单emmm
继续阅读“[线段树][区间等比/等差数列修改] CodeForces – 446C DZY Loves Fibonacci Numbers”

[后缀数组][模板] 求正好出现k次子串个数 HDU6194 string string string

Huh,比赛的时候花了三个小时把这个正解是用后缀自动机的题肝了出来,我也不知道我怎么做到的。

想了很多策略之后发现自己是错的就很难受,最后终于想到正确策略:在height数组上做一个长度为k的滑窗,每次检查滑窗两端点之外的height是否比这一整段内的最小值大,注意这里面的一整段最小值M就是这一整段的公共最长公共前缀的长度,这个东西和他的前缀是在这里出现了k次的,那么怎么知道他是不是在滑窗外面出现呢,和两端点的height比较一下就行了,取两端点中的最大值P,这个说明是之外的点与滑窗两个端点的最大公共前缀,而所有的在滑窗内的满足P<len<=M的前缀都是仅出现了一次的子串!!!

wa的话,需要特判k为1的情况,,因为height这个数组是个间隔定义的东西,所以这种只有一个的需要单独处理,这时候实际上区间内的最长公共前缀就是排名在此的后缀本身

继续阅读“[后缀数组][模板] 求正好出现k次子串个数 HDU6194 string string string”

[线段树][收敛函数][区间修改]

https://cn.vjudge.net/problem/CodeForces-920F

跟上一道HDU的题目很像,也是求快速收敛函数的和,因为有结论n的约数个数期望为sqrt(n)。每次遇到一个数就将其质因数分解然后求约数个数,这里可以开一个1e6的数组把处理过的n存下来,记忆化,就可以省下来很多时间(大概吧呵呵)。另外一个需要注意的点是收敛的终点可能是1也可能是2,我这里的方法是把读入的1全变成2,然后输出的时候减去前缀和差分就行了,因为1是怎么都不会变的,2也是不会变的,这样可以保证正确。

继续阅读“[线段树][收敛函数][区间修改]”

[线段树][优化][特征分析] HDU 4027 Can you answer these queries?

https://cn.vjudge.net/problem/HDU-4027

这个题,本身并没有用到区间修改的什么操作。。如果不加优化就基本可以认为是单点修改区间查询的线段树,但是int64的最大值也只需要6次开根号就会收敛到1,因此我们可以加一个优化就是当子区间每一个都是1的话就不再更新区间(就这一个优化真的可以搞定吗。。。)其他的都跟普通的线段树一样了,只不过初始化建树的时候需要一个单独的点修改函数来操作。
继续阅读“[线段树][优化][特征分析] HDU 4027 Can you answer these queries?”

[单调队列][思维][精度][坑] HDU6319 Problem A. Ascending Rating

一开始脑子里总是想今天听讲时候的set,可是怎么也想不出来这个怎么用set做。然后又以为必须离线因为1e7 ,可是后来发现给了500mb内存。。。就愉快的离线了。离线的话可以从后往前单调队列。坑点一个是运算中间结果long long,另外一个是我自己手残,单调队列的尾指针用了r,和参数r重合然后把他覆盖了。。。。这是最傻的一次错误了吧。。。

继续阅读“[单调队列][思维][精度][坑] HDU6319 Problem A. Ascending Rating”

[AC自动机][字符串][模板][优化] HDU3695 Computer Virus on Planet Pandora

https://cn.vjudge.net/problem/HDU-3695

跟2222几乎一样,求文本中出现了多少个模式串,但是数据量变大了,5e6的长度。这时候用原来的写法已经会tle了,看到别人说用打标记的方式记录trie上一个节点有没有走过,一开始是不理解的,为什么这么做是正确的?后来想了想,AC自动机的算法确定了一个起点之后,沿着fail回溯的路径便已经确定(神奇),所以这条路上被走过的单词尾,再走的时候就会重复,而我们可以简单的把走过的节点计数标志变为-1,而在之后的过程中再遇到就可以不用管这个节点及其之后所有的节点了。注意这个是在while一开始就得判断。

WA的话,是从带括号的那个原串解压过后忘了在最后加’\0’。。。emmmm以后试验这种一定要从大到小试验数据。还有就是模板一定要用自己熟悉的。。原来以为这题问题在于kuangbin的板子不够快后来发现是没标记。。第二个是一开始没意识到q可以不止1位。。

继续阅读“[AC自动机][字符串][模板][优化] HDU3695 Computer Virus on Planet Pandora”

[CF][贪心][枚举][思维] CF1019A

http://codeforces.com/problemset/problem/1019/A

今天想起来这坑还没填。心情差.jpg

当时比赛想了一个小时dp,然后在最后10min意识到可以枚举最后所需要的人数然后贪心。。可是已经没时间来实现了,然后就果断地凉了。今天直接补了

一开始纠结,主要在于,这个决策既得考虑人数又得考虑钱,有点像背包,就很不好操作。但是实际上,n范围只有3000,所以完全可以枚举人数,在这个固定的条件下去考虑对于一特定的人数x需要多少钱,就很容易了:每次先把人数大于等于x的减到x-1,把减去的人加到党派1的支持者数量里,这个过程中挑最小的那些累计起来。在做完这些工作后就是看有没有达到人数x,如果达到了/超过了就说明行了,虽然超过的话就不是正好x但是我们只关心钱数的最小值,如果没有达到,那么还需要从剩下的所有人里从小到大累计够人数才可以。

我这里只排序1次,然后每次设置used数组表示一个人是不是在第一步里用过了。算是n^2复杂度吧。当然这个题数据貌似很水怎么都能过。。

实现的话还有一个问题就是按照我的写法遇到p为1的时候是不能设置used的,因为这个其实是针对于党派1之外的来说的。。。因为这个wa了一发。 继续阅读“[CF][贪心][枚举][思维] CF1019A”

[AC自动机][模板] HDU5880 Family View

https://cn.vjudge.net/problem/HDU-5880

AC自动机模板题,不过判断是否是禁忌串内的这种标记方法还是值得一看的。

主要是理解了AC自动机的板子。。当时比赛没有把这个题写出来也是挫了,其实就是模板题。有一个需要注意的地方是如果禁忌串互相包含怎么操作,这里参考的大佬代码用的pos-1和+1标记是否在括号内的做法,很舒服。

错误的话,把Trie开到main里RE。。本地都RE,然后每个test都要换行,忘了这个PE了一发。

继续阅读“[AC自动机][模板] HDU5880 Family View”