标签:
存在 20% 的数据,输出文件第一行为 1 。
#include<stdio.h> #include<string.h> #define INF 0x3f3f3f3f char s[100010], s1[200010]; int mana[100010], L, next[200010], match[100010], r[100010]; int min(int x, int y) { return x<y?x:y; } void getmana() { mana[0] = 0; int id = 0, right = 0; for(int i = 1; i < L-1; ++i) { if(right > i) mana[i] = min(mana[2*id - i], right - i); else mana[i] = 0; while(s[i+mana[i]+1] == s[i-mana[i]-1] && (i+mana[i]+1) < L && (i-mana[i]-1) >= 0) mana[i]++; if(mana[i]+i > right) { id = i; right = mana[i]+i; } } } void getnext(char *temp) { memset(next, 0, sizeof(next)); next[0] = -1; int i = 0, j = -1; while(temp[i]) { if(j == -1 || temp[i] == temp[j]) { i++; j++; next[i] = j; } else j = next[j]; } } int main() { int i, j, k, l; while(gets(s) != NULL) { L = strlen(s); getmana(); for(i = L-1; i >= 0; --i) s1[L-1-i] = s[i]; s1[L] = '#'; s1[L+1] = '\0'; strcat(s1,s); getnext(s1); for(i = L+1; i <= 2*L+1; ++i) match[i-L-1] = next[i]; memset(r, -1, sizeof(r)); for(i = 1; i <= L; ++i) { if(match[i] > match[i-1]) r[match[i]-1] = i-1; else match[i] = match[i-1]; } for(i = 1; i < L; ++i) { if(r[i] == -1) r[i] = r[i-1]; // printf("%d ", r[i]); } // printf("\n"); int ans[3][2] = {0}, max = 0; bool ok = true; for(i = 1; i < L-1; ++i)//the length must bigger than 3 { j = i+mana[i]+1; if(j >= L || i-mana[i] <= 0) j = L; else { if(r[L-j-1] == -1) j = L; else { if(r[L-j-1] >= i-mana[i]) j = L - match[i-mana[i]]; else j = L - match[r[L-j-1]+1]; } } if(j < L) { if(2*(L-j) + mana[i]*2 + 1 > max) { max = 2*(L-j) + mana[i]*2 + 1; ans[0][0] = r[L-j-1] - L + j + 1; ans[0][1] = L-j; ans[1][0] = i-mana[i]; ans[1][1] = 2*mana[i]+1; ans[2][0] = j; ans[2][1] = L-j; ok = false; // printf("1 %d\n", max); } } else { if(2*mana[i]+1 > max) { max = 2*mana[i]+1; ok = true; ans[1][0] = i-mana[i]; ans[1][1] = 2*mana[i]+1; } } } if(ok) { if(ans[1][1] == 0) ans[1][1] = 1; printf("1\n%d %d\n", ans[1][0]+1, ans[1][1]); } else { printf("3\n"); printf("%d %d\n", ans[0][0]+1, ans[0][1]); printf("%d %d\n", ans[1][0]+1, ans[1][1]); printf("%d %d\n", ans[2][0]+1, ans[2][1]); } } return 0; }
思路:总体思路为枚举字符串中以每个字符为中心的middle部分,然后向两边寻找prefix以及suffix。
首先对于middle我们需要用manacher算法求出每个字符为中心时的middle。
其次我们从题意可以看出suffix必定是从输入的字符串的最后一个字符开始往前数的,那么我们可以求出对于每一个middle的剩下的尾部所能匹配到的最大的prefix。
这也是这道题目的难点所在。
我们先把字符串反转,然后再接上原字符串,并且在2个字符串中间插上一个不相干字符作为分界符,让必定成为suffix的部分成为新字符串的前端。
然后我们求出新字符串的next数组,想一想对于后半部分来说,next所代表的含义:即对于源字符串顺序匹配时所能匹配到的源字符串逆向部分的最大长度。(保存到一个新的数组中,假设为a数组)
这样我们就可以根据a部分再进行反向处理,得到b数组:即从源字符串的第i个字符开始往后的所有部分组成的字符串 所能匹配到的 源字符串的正向部分最大长度的字符串的最右端的位置。
最后对于每一个middle 我们就可以知道它最长的prefix和suffix,这里根据suffix来判断prefix,①如果说prefix的最右端的位置覆盖了middle,那么middle最长的prefix即为0~middle的最左端,由prefix我们又可以根据a知道suffix的最大长度,三个部分求得;②如果说prefix的最右端的位置小于middle,那么我们就知道了prefix,同理根据prefix也可以求出suffix三个部分求得。
Tricky and Clever Password 【KMP+Manacher】【蓝桥杯试题】
标签:
原文地址:http://blog.csdn.net/u014641529/article/details/51334193