02 2014 档案
摘要:昨天的CF自己太挫了。一上来看到A题,就有思路,然后马上敲,但是苦于自己很久没有敲计数的题了,许多函数都稍微回忆了一阵子。A题的主要做法就是将每个数质因数分解,统计每个质因子的个数,对于每个质因子pi的个数k,等价于解一个方程x1+x2+...+xn=k的有多少个非负整数解,学过离散数学或者一些组合数学的就会知道,答案是C(k,n+k-1),但是由于n+k-1可能会很大,我一开始考虑小了,贡献了好多次RE,所以在算组合数的时候只能算出每个数的阶乘以及对应的逆元去算,然后将每个因子算出来的结果乘起来就可以了。B的话写一下就会发现很明显的能够裂项,所以问题就转换成求u(n),v(n),n的大小达到
阅读全文
摘要:这道题当时做的时候觉得是数论题,包含两个01串什么的,但是算重复的时候又很蛋疼,赛后听说是字符串,然后就觉得很有可能。昨天队友问到这一题,在学了AC自动机之后就觉得简单了许多。那个时候不懂AC自动机,不知道什么是状态,因此没有想到有效的dp方法。题意是这样的,给定两个RD串,譬如RRD,DDR这样子的串,然后现在要你向右走(R)m步,向下走(D)n步,问有多少种走法能够包含给定的两个串。一个传统的dp思想是这样的 dp[i][j][x][y][k],表示走了i步R,j步D,x,y表示两个串各匹配了多少各,k表示的是1,2串匹配的一个4进制数(00,01,10,11,你懂的,11表示都匹配了,1
阅读全文
摘要:很早之前听说有一种dp是在图上的dp,然后是在跑SPFA的时候进行dp,所以特地找了一题关于在SPFA的时候dp的。题意:1~a是村庄 a+1~a+b是城堡,存在m条无向边。求由a+b->1的最短路,但是你有很多飞鞋,每双飞鞋可以跑一个固定的距离l,但是跑的时候要是碰到了城堡就要停下来,而且也不能停在路中间。思路和代码参考了下面的这个网址:http://blog.csdn.net/acm_cxlove/article/details/8679230思路:正常来说我们就跑SPFA就可以了,每次从队列里取点更新,但因为有了跑鞋,所以每次取点的时候还有多一种转移途径,因此我们就需要知道每次用了
阅读全文
摘要:题目的介绍以及思路完全参考了下面的博客:http://blog.csdn.net/acm_cxlove/article/details/7964739做这道题主要是为了加强自己对SPFA的代码的训练以及对树dp的一些思路的锻炼。我特地研究了一下树dp的部分for (int i = t; i >= w; i--){ for (int j = i-w; j >= 0; j--){ dp[u][i] = max(dp[u][i], dp[u][j]+dp[v][i - j - w]); } }循环里面是不能搞错顺序的,外层的i逆序显然,但为什么里层会有问题呢? 因为w是可以=0的,这..
阅读全文
摘要:典型的最短路问题,但是多了一个条件,就是每个点属于一个layer,相邻的layer移动,如x层移到x+1层需要花费c.一种显而易见的转化是我把这些边都建出来,但是最后可能会使得边变成O(n^2);网上看到的一些做法就是拆点,假如我给每层做一个平台点,所有点都可以到这个平台,然后再换乘到别的平台里不就可以了吗? 所以对于属于第i层的点我们构造一个i层点的虚拟点,把这些点连到这个平台点,花费为0,相邻平台点之间的花费为c不就可以了吗? 但是问题就出现在这里了,这样的话同一层的点的花费就会变成0,原本可能不可达的变得可达。网上看到的拆点方法有这么两种。A.每层拆两个点,一个点管入,一个点管出,这样的
阅读全文
摘要:又是区间第k大,这次选择这道题是为以后写线段树套平衡树铺路的。Range Tree可以理解成线段树套vector吧,相当于每个结点多存了对应区间的一个排好序的序列。画一下就会知道空间的消耗是nlogn的。然后我们只需要二分答案就可以了,二分的时候相当于是在logn个不相交的小区间里询问#include#include#include#include#include#define maxn 100000using namespace std;vector dat[4*maxn + 50];int a[maxn + 50];int n, q;void build(int k, int l, int
阅读全文
摘要:做这题主要是为了学习一下tarjan的强连通分量,因为包括桥,双连通分量,强连通分量很多的求法其实都可以源于tarjan的这种方法,通过一个low,pre数组求出来。题意:给你许多的A->B ,B->C这样的喜欢的关系,A->B ,B->C也意味着A->C,最后问你被全部别的人喜欢的cow有多少个。如果不告诉你用强连通分量,感觉可能会绕的远一些,但是如果知道了这个思路其实是很显然的。首先是跑出每个强连通分量,在这种情况下,原来的图就变成了一棵树,一棵有有向边的树,然后不难发现,如果这棵树存在一个出度为0的点,那么它就很有可能是答案,为什么是可能呢?因为我们不知道是
阅读全文
摘要:题目的意思很简单,给你一个已经连通的无向图,我们知道,图上不同的边连通分量之间有一定数量的桥,题目要求的就是要你再在这个图上加一条边,使得图的桥数目减到最少。首先要做的就是找出桥,以及每个点所各自代表的连通分量。 找桥的方法就是经典的low[u],pre[v]的判断,这个在大白书上也有比较详尽的介绍。当我们找到桥之后我们当然要把桥边存起来,存的时候就有很多姿势了,因为题目给的点达到200000的级别,所以肯定不能开一个邻接矩阵,所以存的时候要么就开个vector存下所有的桥边,但是遍历索引的时候就会很蛋疼。要么就采用另外一种方法,vector P[i],其中P[i]这个vector里存下了所有
阅读全文
摘要:现在打算重新学习图论的一些基础算法,包括像桥,割顶,双连通分量,强连通分量这些基础算法我都打算重敲一次,因为这些量都是可以用tarjan的算法求得的,这次的割顶算是对tarjan的那一类算法的理解的再次实现吧,后面打算做一下桥的判断和边双连通的关系,边双连通处理的时候如果又重边的话会很不一样,割顶也会相应的不一样,这里的代码是没有考虑重边的,后面再写一个考虑重边的吧。#pragma warning(disable:4996)#include#include#include#include#include#include#include#define maxn 150using namespac
阅读全文
摘要:又是不带修改的区间第k大,这次用的是一个不同的方法,划分树,划分树感觉上是模拟了快速排序的过程,依照pivot不断地往下划分,然后每一层多存一个toleft[i]数组,就可以知道在这一层里从0到i里有多少个被划分到了左子树,知道区间有多少个被分到左子树,就可以一路递归下去,不需要像函数式线段数一样,二分再加query,所以每次询问的复杂度也只是O(nlogn),空间复杂度的话就是O(nlogn),具体的介绍很多个链接都有,具体看下面给出的两个链接,它们对我起到非常大的帮助。http://blog.csdn.net/famousdt/article/details/7064866http://w
阅读全文
摘要:Manacher算法是O(n)求最长回文子串的算法,其原理很多别的博客都有介绍,代码用的是clj模板里的,写的确实是异常的简洁,现在的我只能理解个大概,下面这个网址的介绍比较接近于这个模板,以后再好好理解,我现在先放一放http://www.starvae.com/?p=212#pragma warning(disable:4996)#include#include#include#include#include#include#includeusing namespace std;void palindrome(char cs[], int len[], int n) { //len[i]
阅读全文
摘要:跟上面那篇轮廓线dp是一样的,但是多了两个条件,一个是在原图上可能有些点是不能放的(即障碍),所以转移的时候要多一个判断color[i][j]是不是等于1什么的,另外一个是我们可以有多的1*1的骨牌,1*1的骨牌使用数量一定要在[c,d]之间,所以状态加多一维,转移的时候多一种情况(放1的)。那么怎么初始化呢?有两种方法,一种是dp[0][0][d]=1,最后的答案的因为一定要用[c,d]之间,所以答案是dp[(t+1)&1][0][0~d-c].另外一种是dp[0][0][c~d]=1,最后答案是dp[(t+1)&1][0][0]学了就觉得很简单,60行不到的代码让我们和银奖
阅读全文
摘要:第一道轮廓线dp,因为不会轮廓线dp我们在南京区域赛的时候没有拿到银,可见知识点的欠缺是我薄弱的环节。题目就是要你用1*2的多米诺骨排填充一个大小n*m(n,m#include#include#include#include#include#include#define ll long longusing namespace std;int n, m;ll dp[2][1 > n >> m &&(n||m)) { memset(dp, 0, sizeof(dp)); ll *cur, *next; cur = dp[0]; next = dp[1]; cur[
阅读全文
摘要:今天学了很多关于树状数组的技巧。一个是利用树状数组可以简单的实现段更新,点询问(二维的段更新点询问也可以),每次修改只需要修改2个角或者4个角就可以了,另外一个技巧就是这题,原本用线段树做,现在可以用树状数组做的题,只需多维护一个bit即可。具体的思路见下面的链接:http://hi.baidu.com/billdu/item/053f6a15ca301b0a8ebde400要理解里面的橙色块求的时候是打竖看的,不是打横看的。#pragma warning(disable:4996)#include#include#include#include#include#include#include
阅读全文
摘要:神一般的二维区间更新,运用二维树状数组会有神奇的效果。更改四个角实现区间更改的效果实在是太神奇了。。#pragma warning(disable:4996)#include#include#include#include#include#include#define maxn 1000using namespace std;int bit[maxn + 50][maxn + 50];int n;void inc(int i, int j,int m){ for (; i 0; i -= i&-i){ for (int tmpj = j; tmpj > 0; tmpj -= tm
阅读全文
摘要:给你一个字符串,然后询问它第k小的factor,坑的地方在于spoj实在是太慢了,要加各种常数优化,字符集如果不压缩一下必t。。#pragma warning(disable:4996)#include#include#include#include#include#include#define maxn 90050using namespace std;struct State{ State *suf, *go[26]; int val, cnt; char transch; State() :suf(0), val(0){ memset(go, 0, sizeof(go)); }}*ro.
阅读全文
摘要:多串的LCS,注意要利用拓扑序更新suf的len。我用min,max,三目会超时,所以都改成了if,else#pragma warning(disable:4996)#include#include#include#include#include#include#define maxn 100050using namespace std;struct State{ State *suf, *go[26]; int val, len[2]; State() :suf(0), val(0){ memset(go, 0, sizeof(go)); memset(len, 0, sizeof(le..
阅读全文
摘要:用后缀自动机求两个长串的最长公共子串,效果拔群。多样例的时候memset要去掉。解题思路就是跟CLJ的一模一样啦。#pragma warning(disable:4996)#include#include#include#include#include#include#define maxn 250050using namespace std;struct State{ State *suf, *go[26]; int val; State() :suf(0), val(0){ memset(go, 0, sizeof(go)); }}*root, *last;State statePool.
阅读全文
摘要:人生第一道后缀自动机,总是值得纪念的嘛。。后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边。许多铺垫的理论似懂非懂。然后看了下自动机的构造发现代码倒是挺简单,但是理解原理却是十分的困难,最后在网上找到一篇带例子的讲解帖子,我感觉算是能够说服我的吧放个链接:http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html本题也是CLJ论文里的题,关键是如何求right集的大小,这里的求right集的大小我给个个人的理解,首先是按拓扑序吧,那三行for就有点像基数
阅读全文
摘要:最近在学习字符串的知识,在字符串上我跟大一的时候是没什么区别的,所以恶补了很多基础的算法,今天补了一下字符串哈希,看的是大一新生的课件学的,以前觉得字符串哈希无非就是跟普通的哈希没什么区别,倒也没觉得有什么特别大的用处,敲一敲才发现其实讲究还是比较多的。哈希冲突是常有的事,换一下mod,换一下进制数才有可能过,另外一种说法是用两个互质的量做hash,如果两个都相等的话那冲突就会少很多,这个倒没有做过多大的尝试,侥幸地过了一下这道题#pragma warning(disable:4996)#include#include#include#include#include#include#defin
阅读全文
摘要:POJ上的,ZOJ上的OJ的最长回文子串数据量太大,用后缀数组的方法非常吃力,所以只能挑个数据量小点的试下,真要做可能还是得用manacher。贴一下代码两个小错,一个是没弄懂string类的substr的用法是S.substr(i,len)从i开始的长度为len的一段。另外一个是RMQ的时候,询问rk[i],rk[j]的最长前缀应该是等效于求lcp[rk[i]] lcp[rk[j]-1]这一段,这个要在询问的时候注意一下。#include#include#include#include#include#include#include#define maxn 1000050using name
阅读全文
摘要:回顾一下一些基础算法,Sparse Table有种dp的感觉,写起来有点棘手吧,主要是因为下标的问题,贴一记代码,等下写一个非递归的线段树试试。#pragma warning(disable:4996)#include#include#include#include#include#include#include#define maxn 50000#define max_logn 20using namespace std;int dmin[maxn+20][max_logn];int dmax[maxn+20][max_logn];int a[maxn+50];int n,m;int mai
阅读全文
摘要:学后缀数组后的一道裸题。先来讲讲收获,作为字符串初学者,后缀数组也是刚刚在学,所幸的是有一篇好的论文《后缀数组--处理字符串的有力工具》by 罗穗骞,里面非常详尽地介绍了有关后缀数组的概念,也就是sa[i]和rk[i]表示的是什么。理解了它们互为逆运算后就不难理解sa[rk[i]]=i rk[sa[i]]=i,所以知道其中一个就可以知道另外一个,然后学习了一下后缀数组中的倍增算法构建,虽然效率比不上线性的算法,但是胜在好理解,好写。当然大神的代码我是不怎么懂,我就翻阅了另一本书《挑战程序设计竞赛》里的代码,总之就是两个材料一起看,搞懂了什么是高度数组lcp, 也知道了h[i]>=h[i-
阅读全文
浙公网安备 33010602011771号