有关“字符串”的处理方法
2013-11-03 22:39
162 查看
[b]一,KMP模式匹配[/b]
const int kind = 26; const int NN = 333333; int cnt;//ac状态数 char str[NN];//所有的字符接在一起 int pos[NN]; int fail[NN];//每个状态的fail指针 int child[NN][kind];//trie树 int ans;//最终答案 int val[NN];//每个单词输入的value int tal;//时间戳状态数 vector<int>v[NN];//fail树 int in[NN];//时间戳 int out[NN]; int mx[NN<<2];//线段树 inline int newNode(){ ++cnt; for(int i=0; i<kind; ++i) child[cnt][i] = -1; return cnt; } void insert(char *str, int root, int id){ int p = root; int len = strlen(str); for(int i=0; i < len; ++i){ int k = str[i] - 'a'; if(child[p][k] == -1) child[p][k] = newNode(); p = child[p][k]; } } void build_fail(int root){ queue<int>q; int p = root; q.push(p); while(!q.empty()){ p = q.front(); q.pop(); if(p) v[fail[p]].push_back(p); for(int k = 0; k < kind; ++k){ int tmp = child[p][k]; if(tmp != -1){ if(p!=root) fail[tmp] = child[fail[p]][k]; else fail[tmp] = root; q.push(tmp); } else { if(p!=root) child[p][k] = child[fail[p]][k]; else child[p][k] = root; } } } } void dfs(int s){ in[s] = ++tal; int len = v[s].size(); for(int i = 0; i < len; ++i){ dfs(v[s][i]); } out[s] = tal; v[s].clear(); } int query(int l, int r, int k, int L){ if(l==L && r==L) return mx[k]; int mid = (l+r)>>1; mx[k<<1] = max(mx[k<<1], mx[k]); mx[k<<1|1] = max(mx[k<<1|1], mx[k]); if(L<=mid) return query(l, mid, k<<1, L); else return query(mid+1, r, k<<1|1, L); } void update(int l, int r, int k, int L, int R, int x){ if(mx[k] >= x) return; if(l==L && r==R){ mx[k] = x; return; } int mid = (l+r)>>1; if(R<=mid) update(l, mid, k<<1, L, R, x); else if(L>mid) update(mid+1, r, k<<1|1, L, R, x); else{ update(l, mid, k<<1, L, mid, x); update(mid+1, r, k<<1|1, mid+1, R, x); } } int main(){ int n, m, tt=0; scanf("%d", &m); while(m--){ scanf("%d", &n); cnt = -1; int root = newNode(); pos[0] = 0; for(int i = 1; i <= n; ++i){ scanf("%s%d", str + pos[i-1], &val[i]); insert(str + pos[i-1], root, i); pos[i] = pos[i-1] + strlen(str + pos[i-1]); } build_fail(root); tal = 0; dfs(0); memset(mx, 0, sizeof(mx)); ans = 0; for(int i = 1; i <= n; ++i){ int p = 0; int preTmp = 0; for(int j = pos[i-1]; j < pos[i]; ++j){//这里虽然是两层循环,其实一共只有pos int v = val[i] * (j==pos[i]-1); p = child[p][str[j]-'a']; int tmp = query(1, tal, 1, in[p]); tmp = max(preTmp, tmp) + v; ans = max(ans, tmp); update(1, tal, 1, in[p], out[p], tmp); preTmp = tmp; } } printf("Case #%d: ", ++tt); cout<<ans<<endl; } return 0; }
View Code
POJ 2778
检测所有可能的n位DNA串有多少个串中不含有指定的病毒片段。合法的DNA只能由ACTG四个字符构成。
题目将给出10个以内的病毒片段,每个片段长度不超过10。数据规模n<=2 000 000 000。
以ATC,AAA,GGC,CT这四个病毒片段为例。我们找出所有病毒片段的前缀,把n位DNA分为以下7类:以AT结尾、以AA结尾、以GG结尾、以?A结尾、以?G结尾、以?C结尾和以??结尾。其中问号表示“其它情况”,它可以是任一字母,只要这个字母不会让它所在的串成为某个病毒的前缀。显然,这些分类是全集的一个划分(交集为空,并集为全集)。现在,假如我们已经知道了长度为n-1的各类DNA中符合要求的DNA个数,我们需要求出长度为n时各类DNA的个数。我们可以根据各类型间的转移构造一个边上带权的有向图。例如,从AT不能转移到AA,从AT转移到??有4种方法(后面加任一字母),从?A转移到AA有1种方案(后面加个A),从?A转移到??有2种方案(后面加G或C),从GG到??有2种方案(后面加C将构成病毒片段,不合法,只能加A和T)等等。这个图的构造过程类似于用有限状态自动机做串匹配。然后,我们就把这个图转化成矩阵,让这个矩阵自乘n次即可。最后输出的是从??状态到所有其它状态的路径数总和。
[b]五,后缀数组[/b]
1. sa[i]后缀的字典序为i的首字母在原串中位置2. rank[i]从第i个字符开始的后缀在sa[]中下标位置,i=sa[rank[i]]
height[i]后缀字典序排列第i个与i-1个的最长前缀长度,最长重复子串
对height[]的最小RMQ即是后缀的最长公共前缀
1.求一个字符串的最长重复子串,可以重叠,直接求height数组中的最大值。
2.求一个字符串的最长重复子串,要求这两个子串不重叠。先对变化求height,然后二分答案,将问题转化为证明是否存在长度为k的不重合序列
根据后缀数组的性质可知height数组是呈波峰状的,找到所有height大于k的组,若有一组中最小的sa和最大的sa之差大于k,则存在。poj1743。
3.两个字符串的最长公共子串,将两个字符串拼起来,利用height数组找到sa[i]与sa[i-1]在不同字符串的最大值。poj2774。
4.一个字符串的最长回文,poj3794,方法是将字符串反转然后连在其后面,中间用一个未出现的符号隔开,形如str$reverse(str)#,写出模板后,利用height数组,判断是否是来自这两个字符串。
[b]六,后缀自动机[/b]
[b]七,回文问题[/b]
http://www.cnblogs.com/AbandonZHANG/archive/2012/07/17/2598256.html相关文章推荐
- c#.net常见字符串处理方法
- 通过Python的内置字符串处理函数来处理字符串的方法和整理
- 解决asp.net Sharepoint无法连接发布自定义字符串处理程序,不能进行输出缓存处理的方法
- 简介:如何利用IndexOf和SubString两种方法处理字符串
- Python的字符串处理方法
- 【写一个自己的js库】 3.添加几个处理字符串的方法
- 总结-处理字符串常用方法类
- 存储过程处理字符串数组的方法
- 深入解析C++中的字符数组和处理字符串的方法
- 跨平台程序的UNICODE字符串处理方法。
- PHP处理字符串的简单方法
- 有关qt的信号槽错误的处理方法
- c#.net常见字符串处理方法
- 有关字符串的一些方法
- 几个字符串处理方法:
- (华为机试大备战)java。多了解了解最常用的那个类库的方法对处理字符串的方法
- Oracle中“字符串中的字符大小写敏感处理方法”
- mysql字符串不支持emoj表情的处理方法
- Python字符串处理之count()方法的使用
- PHP处理Json字符串解码返回NULL的解决方法