1. 程式人生 > >Kuangbin專題十六KMP & 擴充套件KMP & Manacher(M~Z)

Kuangbin專題十六KMP & 擴充套件KMP & Manacher(M~Z)

You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. 

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string. 

Output

There should be one line per test case containing the length of the largest string found. 

Sample Input

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output

2
2

暴力列舉+KMP

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 110
#define M 20010
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

string s[N];
int n, ls;

int nxt1[N], nxt2[N];
void getnxt(const string & a, int * nxt)
{
    int la = a.length(), k = -1; nxt[0] = -1;
    for(int i = 0; i < la; ) {
        if(k == -1 || a[i] == a[k]) {
            if(a[++i] == a[++k]) nxt[i] = nxt[k];
            else nxt[i] = k;
        }
        else k = nxt[k];
    }
}

bool kmp(const string & a, const string & b, int * nxt)
{
    int la = a.length(), lb = b.length();
    int j = 0;
    for(int i = 0; i < lb; ) {
        if(j == -1 || b[i] == a[j]) {
            ++i; ++j;
        }
        else j = nxt[j];
//cout << j << endl;
        if(j >= la) return true;
    }
    return false;
}

string getstr(const string & a, int l, int r)
{
    string ans = "";
    rep(i, l, r - 1) ans += a[i];
    return ans;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int t;
    scanf("%d", &t);

    while(t--) {
        scanf("%d", &n);
        rep(i, 1, n) cin >> s[i];

        ls = s[1].length();

        bool f = false;
        rrep(i, ls, 1) {
            for(int j = 0; j + i <= ls; j++) {
                string tmp1 = getstr(s[1], j, j + i);
///cout << tmp1 << endl;
                getnxt(tmp1, nxt1);
                string tmp2 = tmp1;
                reverse(tmp2.begin(), tmp2.end());
                getnxt(tmp2, nxt2);
                bool flag = true;
                rep(k, 2, n) {
                    if(!kmp(tmp1, s[k], nxt1) && !kmp(tmp2, s[k], nxt2)) {
   // cout << k << ' ' << tmp1 << ' ' << s[k] << endl;
                        flag = false;
                        break;
                    }
                }
                if(flag) {
                    f = true; break;
                }
            }
            if(f) {
                printf("%d\n", i);
                break;
            }
        }

        if(!f) puts("0");
    }

    return 0;
}

Beside other services, ACM helps companies to clearly state their “corporate identity”, which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently asked ACM for a help with their new identity. IBM do not want to change their existing logos and trademarks completely, because their customers are used to the old ones. Therefore, ACM will only change existing trademarks instead of creating new ones.  After several other proposals, it was decided to take all existing trademarks and find the longest common sequence of letters that is contained in all of them. This sequence will be graphically emphasized to form a new logo. Then, the old trademarks may still be used while showing the new identity.  Your task is to find such a sequence.

Input

The input contains several tasks. Each task begins with a line containing a positive integer N, the number of trademarks (2 ≤ N ≤ 4000). The number is followed by N lines, each containing one trademark. Trademarks will be composed only from lowercase letters, the length of each trademark will be at least 1 and at most 200 characters.  After the last trademark, the next task begins. The last task is followed by a line containing zero.

Output

For each task, output a single line containing the longest string contained as a substring in all trademarks. If there are several strings of the same length, print the one that is lexicographically smallest. If there is no such non-empty string, output the words “IDENTITY LOST” instead.

Sample Input

3
aabbaabb
abbababb
bbbbbabb
2
xyz
abc
0

Sample Output

abb
IDENTITY LOST

暴力

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 210
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int nxt[N];
void getnxt(char * s, int ls)
{
    int k = -1; nxt[0] = -1;
    for(int i = 0; i < ls; ) {
        if(k == -1 || s[i] == s[k]) {
            if(s[++i] == s[++k]) nxt[i] = nxt[k];
            else nxt[i] = k;
        }
        else k = nxt[k];
    }
}

bool kmp(char * a, int la, char * b, int lb)
{
    for(int i = 0, j = 0; i < la; ) {
        if(j == -1 || a[i] == b[j]) {
            ++i; ++j;
        }
        else j = nxt[j];
        if(j == lb) return true;
    }
    return false;
}

int n, ls;
char s[4100][N], tmp[N], ans[N];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(scanf("%d", &n) && n) {
        rep(i, 1, n) scanf("%s", s[i]);
        ls = strlen(s[1]);

        bool f = false;
        rep(i, 0, ls) ans[i] = 'z';
        ans[ls + 1] = '\0';
        rrep(i, ls, 1) {
            for(int j = 0; j + i <= ls; j++) {
                rep(k, 0, i - 1) tmp[k] = s[1][k + j];
                tmp[i] = '\0';
                getnxt(tmp, i);
//cout << tmp << endl;
                bool flag = true;
                rep(k, 2, n) {
                    if(!kmp(s[k], strlen(s[k]), tmp, i)) {
                        flag = false;
                        break;
                    }
                }
                if(flag) {
                    f = true;
                    if(strcmp(tmp, ans) < 0) strcpy(ans, tmp);
                }
            }
            if(f) break;
        }
        if(!f) puts("IDENTITY LOST");
        else puts(ans);
    }

    return 0;
}

Give you a string with length N, you can generate N strings by left shifts. For example let consider the string “SKYLONG”, we can generate seven strings:  String Rank  SKYLONG 1  KYLONGS 2  YLONGSK 3  LONGSKY 4  ONGSKYL 5  NGSKYLO 6  GSKYLON 7  and lexicographically first of them is GSKYLON, lexicographically last is YLONGSK, both of them appear only once.    Your task is easy, calculate the lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), its times, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also. 

Input

  Each line contains one line the string S with length N (N <= 1000000) formed by lower case letters.

Output

Output four integers separated by one space, lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), the string’s times in the N generated strings, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.

Sample Input

abcder
aaaaaa
ababab

Sample Output

1 1 6 1
1 6 1 6
1 3 2 3

串的最小表示法和最大表示法,表示出來後kmp。

當時學最大最小表示法的時候還看懂了,這會兒寫部落格又忘了原理了,佛了佛了當板子吧。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int nxt[N];
void getnxt(char * s, int ls)
{
    int k = -1; nxt[0] = -1;
    for(int i = 0; i < ls; ) {
        if(k == -1 || s[i] == s[k]) {
            if(s[++i] == s[++k]) nxt[i] = nxt[k];
            else nxt[i] = k;
        }
        else k = nxt[k];
    }
}

int minr(char * s, int ls)
{
    int i = 0, j = 1, k;
    while(i < ls && j < ls) {
        k = 0;
        while(s[(i + k) % ls] == s[(j + k) % ls] && k < ls) k++;
        if(k == ls) return min(i, j);
        if(s[(i + k) % ls] > s[(j + k) % ls]) i = max(i + k + 1, j + 1);
        else j = max(j + k + 1, i + 1);
    }
    return min(i, j) % ls;
}
int maxr(char * s, int ls)
{
    int i = 0, j = 1, k;
    while(i < ls && j < ls) {
        k = 0;
        while(s[(i + k) % ls] == s[(j + k) % ls] && k < ls) k++;
        if(k == ls) return min(i, j);
        if(s[(i + k) % ls] < s[(j + k) % ls]) i = max(i + k + 1, j + 1);
        else j = max(j + k + 1, i + 1);
    }
    return min(i, j) % ls;
}

char s[N];
int ls, p1, p2, ans;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%s", s)) {
        ls = strlen(s);
        p1 = minr(s, ls) + 1;
        p2 = maxr(s, ls) + 1;
        getnxt(s, ls);
        if(ls % (ls - nxt[ls]) == 0)
            ans = ls / (ls - nxt[ls]);
        else ans = 1;
        printf("%d %d %d %d\n", p1, ans, p2, ans);
    }

    return 0;
}

Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100,tell me  How many kinds of necklaces total have.(if two necklaces can equal by rotating ,we say the two necklaces are some).  For example 0110 express a necklace, you can rotate it. 0110 -> 1100 -> 1001 -> 0011->0110. 

Input

The input contains multiple test cases.  Each test case include: first one integers n. (2<=n<=10000)  Next n lines follow. Each line has a equal length character string. (string only include '0','1'). 

Output

For each test case output a integer , how many different necklaces.

Sample Input

4
0110
1100
1001
0011
4
1010
0101
1000
0001

Sample Output

1
2

最大最小表示法。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

string minr(const string & s, int ls)
{
    int i = 0, j = 1, k, p;
    bool f = false;

    while(i < ls && j < ls) {
        k = 0;
        while(s[(i + k) % ls] == s[(j + k) % ls] && k < ls) k++;
        if(k == ls) {
            f = true;
            p = min(i, j);
        }
        if(s[(i + k) % ls] > s[(j + k) % ls]) i = max(i + k + 1, j + 1);
        else j = max(j + k + 1, i + 1);
    }
    if(!f) p = min(i, j) % ls;
    string ans = "";
    int cnt = ls, l = 0;
    while(cnt--) {
        ans += s[(p + l) % ls];
        l++;
    }
    return ans;
}
set<string> st;
int n;
string s;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d", &n)) {
        st.clear();
        rep(i, 1, n) {
            cin >> s;
            st.insert(minr(s, s.length()));
        }
        printf("%d\n", (int)st.size());
    }

    return 0;
}

For each prefix with length P of a given string S,if

S[i]=S[i+P] for i in [0..SIZE(S)-p-1],

then the prefix is a “period” of S. We want to all the periodic prefixs.

Input

Input contains multiple cases.

The first line contains an integer T representing the number of cases. Then following T cases.

Each test case contains a string S (1 <= SIZE(S) <= 1000000),represents the title.S consists of lowercase ,uppercase letter.

Output

For each test case, first output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the number of periodic prefixs.Then output the lengths of the periodic prefixs in ascending order.

Sample Input

4
ooo
acmacmacmacmacma
fzufzufzuf
stostootssto

Sample Output

Case #1: 3
1 2 3
Case #2: 6
3 6 9 12 15 16
Case #3: 4
3 6 9 10
Case #4: 2
9 12

求所有字首字尾匹配的長度。和上面某某題目差不多。

首先肯定nxt[ls]是失配指標且這個匹配配到了尾巴,所以ls - nxt[ls]是答案。

然後肯定nxt[ls]到ls之間都沒有失配,所以下一個失配的就是nxt[ls],或者是迴圈節那種。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

char s[N];
int ls;
int ans[N], l, p;

int nxt[N];
void getnxt()
{
    int k = -1; nxt[0] = -1;
    for(int i = 0; i < ls;) {
        if(k == -1 || s[i] == s[k]) nxt[++i] = ++k;
        else k = nxt[k];
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int t;
    scanf("%d", &t);

    rep(Case, 1, t) {
        scanf("%s", s);
        ls = strlen(s);
        getnxt();
//rep(i, 0, ls) cout << i << ' ' << nxt[i] << endl;
        l = 0;
        p = ls;
        while(p > 0) {
            ans[l++] = ls - nxt[p];
            p = nxt[p];
        }
        sort(ans, ans + l);
        printf("Case #%d: %d\n", Case, l);
        for(int i = 0; i < l; i++) {
            printf("%d%c", ans[i], i == l - 1?'\n':' ');
        }
    }

    return 0;
}

模擬沒高興寫,嫌煩人,佛了佛了。

After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit.  One of these treasures is a necklace made up of 26 different kinds of gemstones, and the length of the necklace is n. (That is to say: n gemstones are stringed together to constitute this necklace, and each of these gemstones belongs to only one of the 26 kinds.)  In accordance with the classical view, a necklace is valuable if and only if it is a palindrome - the necklace looks the same in either direction. However, the necklace we mentioned above may not a palindrome at the beginning. So the head of state decide to cut the necklace into two part, and then give both of them to General Li.  All gemstones of the same kind has the same value (may be positive or negative because of their quality - some kinds are beautiful while some others may looks just like normal stones). A necklace that is palindrom has value equal to the sum of its gemstones' value. while a necklace that is not palindrom has value zero.  Now the problem is: how to cut the given necklace so that the sum of the two necklaces's value is greatest. Output this value.   

Input

The first line of input is a single integer T (1 ≤ T ≤ 10) - the number of test cases. The description of these test cases follows.  For each test case, the first line is 26 integers: v 1, v 2, ..., v 26 (-100 ≤ v i≤ 100, 1 ≤ i ≤ 26), represent the value of gemstones of each kind.  The second line of each test case is a string made up of charactor 'a' to 'z'. representing the necklace. Different charactor representing different kinds of gemstones, and the value of 'a' is v 1, the value of 'b' is v 2, ..., and so on. The length of the string is no more than 500000.   

Output

Output a single Integer: the maximum value General Li can get from the necklace.

Sample Input

2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
aba
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
acacac

Sample Output

1
6

這題題意一開始讀錯了,以為項鍊是迴圈的,要切兩刀完全不會寫,其實只是一條鏈切一刀。

思路是列舉切點然後對每個切點判斷兩邊是否是迴文串。

判斷是否是迴文可以用馬拉車或者exkmp。

Manacher:

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 500010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int val[30];
char Ma[N * 2];
int Mp[N * 2], l;

int Manacher(char * s, int len)
{
    l = 0;
    Ma[l++] = '$'; Ma[l++] = '#';
    for(int i = 0; i < len; i++) {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = 0;

    int mx = 0, id = 0;
    for(int i = 1; i < l; i++) {
        Mp[i] = mx > i?min(mx - i, Mp[2 * id - i]):1;
        while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
        if(i + Mp[i] > mx) {
            id = i;
            mx = i + Mp[i];
        }
    }
}

char s[N];
int ls, sum[N], ans, tmp;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int t;
    scanf("%d", &t);

    while(t--) {
        rep(i, 0, 25) scanf("%d", &val[i]);
        scanf("%s", s);
        ls = strlen(s);

        Manacher(s, ls);

        sum[0] = 0;
        rep(i, 0, ls - 1) sum[i + 1] = val[s[i] - 'a'] + sum[i];

        ans = 0;
        rep(i, 2, ls) {
            tmp = 0;
            if(Mp[i] == i) tmp += sum[i - 1];
            //if(Mp[ls * 2 - 1 - (ls - i + 1)] + ls * 2 - 1 - (ls - i + 1) == ls * 2 - 1) tmp += sum[ls - 1] - sum[i * 2 - 1];
            if(Mp[ls + i] + ls + i == l) tmp += (sum[ls] - sum[i - 1]);
            ans = max(ans, tmp);
        }

        printf("%d\n", ans);
    }

    return 0;
}

exkmp:



#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 500010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int nxt0[N], ext0[N];
int nxt1[N], ext1[N];
void getnxt(char *s, int ls, int *nxt)
{
    nxt[0] = ls;
    int j = 0;
    while(j + 1 < ls && s[j] == s[j + 1]) j++;
    nxt[1] = j;
    int k = 1;
    for(int i = 2; i < ls; i++) {
        int R = nxt[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < R + 1) nxt[i] = L;
        else {
            int j = max(0, R - i + 1);
            while(i + j < ls && s[j] == s[i + j]) j++;
            nxt[i] = j;
            k = i;
        }
    }
}
void exkmp(char *s, int ls, char *t, int lt, int *nxt, int *ext)
{
    getnxt(t, lt, nxt);
    int j = 0;
    while(j < ls && j < lt && s[j] == t[j]) j++;
    ext[0] = j;
    int k = 0;
    for(int i = 1; i < ls; i++) {
        int R = ext[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < R + 1) ext[i] = L;
        else {
            int j = max(0, R - i + 1);
            while(i + j < ls && j < lt && s[i + j] == t[j]) j++;
            ext[i] = j;
            k = i;
        }
    }
}

int val[30];
char s[N], t[N];
int ls, sum[N], ans, tmp;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int T;
    scanf("%d", &T);

    while(T--) {
        rep(i, 0, 25) scanf("%d", &val[i]);
        scanf("%s", s);
        ls = strlen(s);

        sum[0] = 0;
        rep(i, 0, ls - 1) sum[i + 1] = val[s[i] - 'a'] + sum[i];

        rep(i, 0, ls - 1) t[i] = s[ls - i - 1];
        t[ls] = '\0';

        exkmp(t, ls, s, ls, nxt0, ext0);
        exkmp(s, ls, t, ls, nxt1, ext1);
//rep(i, 0, ls - 1) cout << i << ' ' << ext0[i] << ' ' << ext1[i] << endl;
//rep(i, 1, ls) cout << sum[i] << endl;
        ans = 0;
        rep(i, 1, ls - 1) {
            tmp = 0;
            int p = ls - i;
//cout << p << ' ' << ext0[p] + p << endl;
            if(ext0[p] + p >= ls) tmp += sum[i];
            if(ext1[i] + i >= ls) tmp += sum[ls] - sum[i];
//cout << ext1[i] + i <<endl;
            ans = max(ans, tmp);
        }

        printf("%d\n", ans);
    }

    return 0;
}

A word is called a palindrome if we read from right to left is as same as we read from left to right. For example, "dad", "eye" and "racecar" are all palindromes, but "odd", "see" and "orange" are not palindromes.

Given n strings, you can generate n × n pairs of them and concatenate the pairs into single words. The task is to count how many of the so generated words are palindromes.

Input

The first line of input file contains the number of strings n. The following n lines describe each string:

The i+1-th line contains the length of the i-th string li, then a single space and a string of li small letters of English alphabet.

You can assume that the total length of all strings will not exceed 2,000,000. Two strings in different line may be the same.

Output

Print out only one integer, the number of palindromes.

Sample Input

3
1 a
2 ab
2 ba

Sample Output

5

Hint

The 5 palindromes are:  a a a ba ab a ab ba ba ab 

這題好難。。。

把n個串丟進Trie圖,然後用原串去匹配,原串長了就看原串長的部分是否是迴文串,否則就看這個節點鞋面的串有幾個迴文串。

昂全部是抄的大佬的程式碼。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

const int MAXN = 2000000;
char buf[MAXN + 1], tmp[MAXN + 1];
int n, l[MAXN], sz[MAXN], ex[MAXN], nxt[MAXN];
char s[MAXN], t[MAXN];
ll ans;

namespace trie {
    const int MAXV = MAXN + 1, MAXE = 10000000;
    int ecnt, begin[MAXV], to[MAXE], nxt[MAXE], end[MAXV], cnt[MAXV];
    char val[MAXV];

    int id, root;

    void init() {
        ecnt = 0;
        memset(begin, -1, sizeof begin);
        id = 0;
        root = id++;
        val[root] = -1;
    }

    void addedge(int u, int v) {
        nxt[ecnt] = begin[u];
        begin[u] = ecnt;
        to[ecnt++] = v;
    }

    void ins(int sz) {
        int pos = root;
        for(int i = 0; i < sz; i++) {
            int t = s[i] - 'a';
            if(ex[i] == sz - i) cnt[pos]++;
            bool exi = 0;
            for(int now = begin[pos]; now != -1; now = nxt[now])
            if(val[to[now]] == t) {
                exi = 1;
                pos = to[now];
            }
            if(!exi) {
                int v = id++;
                addedge(pos, v);
                val[v] = t;
                pos = v;
            }
        }
        end[pos]++;
    }

    void go(int sz) {
        int pos = root;
        for(int i = 0; i < sz; i++) {
            int t = s[i] - 'a';
            bool exi = 0;
            for(int now = begin[pos]; now != -1; now = nxt[now])
            if(val[to[now]] == t) {
                exi = 1;
                pos = to[now];
            }
            if(!exi) return;
            if(end[pos]) {
                if(i < sz - 1 && ex[i + 1] == sz - i - 1) ans += end[pos];
                else if(i == sz - 1) ans += end[pos];
            }
        }
        ans += cnt[pos];
    }
}

void getnxt(int len)
{
    nxt[0] = len;
    int j = 0;
    while(j + 1 < len && t[j] == t[j + 1]) j++;
    nxt[1] = j;
    int k = 1;
    for(int i = 2; i < len; i++) {
        int P = nxt[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < P + 1) nxt[i] = L;
        else {
            j = max(P - i + 1, 0);
            while(i + j < len && t[i + j] == t[j]) j++;
            nxt[i] = j;
            k = i;
        }
    }
}
void exkmp(int len)
{
    getnxt(len);
    int j = 0;
    while(j < len && s[j] == t[j]) j++;
    ex[0] = j;
    int k = 0;
    for(int i = 1; i < len; i++) {
        int P = ex[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < P + 1) ex[i] = L;
        else {
            j = max(0, P - i + 1);
            while(i + j < len && s[i + j] == t[j]) j++;
            ex[i] = j;
            k = i;
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int n, tot = 0;
    scanf("%d", &n);
    rep(i, 0, n - 1) {
        scanf("%d%s", &sz[i], buf + tot);
        l[i] = tot;
        tot += sz[i];
    }
    trie::init();
///cout << "aaa" << endl;
    rep(i, 0, n - 1) {
        rep(j, 0, sz[i] - 1) s[j] = buf[l[i] + sz[i] - j - 1];
        rep(j, 0, sz[i] - 1) t[j] = buf[l[i] + j];
        s[sz[i]] = t[sz[i]] = '\0';
        exkmp(sz[i]);
        trie::ins(sz[i]);
    }
    rep(i, 0, n - 1) {
        rep(j, 0, sz[i] - 1) s[j] = buf[l[i] + j];
        rep(j, 0, sz[i] - 1) t[j] = buf[l[i] + sz[i] - j - 1];
        s[sz[i]] = t[sz[i]] = '\0';
        exkmp(sz[i]);
        trie::go(sz[i]);
    }
    printf("%lld\n", ans);

    return 0;
}

Andy the smart computer science student was attending an algorithms class when the professor asked the students a simple question, "Can you propose an efficient algorithm to find the length of the largest palindrome in a string?"  A string is said to be a palindrome if it reads the same both forwards and backwards, for example "madam" is a palindrome while "acm" is not.  The students recognized that this is a classical problem but couldn't come up with a solution better than iterating over all substrings and checking whether they are palindrome or not, obviously this algorithm is not efficient at all, after a while Andy raised his hand and said "Okay, I've a better algorithm" and before he starts to explain his idea he stopped for a moment and then said "Well, I've an even better algorithm!".  If you think you know Andy's final solution then prove it! Given a string of at most 1000000 characters find and print the length of the largest palindrome inside this string.

Input

Your program will be tested on at most 30 test cases, each test case is given as a string of at most 1000000 lowercase characters on a line by itself. The input is terminated by a line that starts with the string "END" (quotes for clarity). 

Output

For each test case in the input print the test case number and the length of the largest palindrome. 

Sample Input

abcbabcbabcba
abacacbaaaab
END

Sample Output

Case 1: 13
Case 2: 6

馬拉車板子題

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
int Case = 1;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

char Ma[N * 2];
int Mp[N * 2];

int manacher(char *s, int ls)
{
    int l = 0;
    Ma[l++] = '@';
    Ma[l++] = '#';
    for(int i = 0; i< ls; i++) {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = '\0';
    int mx = 0, d = 0;
    for(int i = 0; i < l; i++) {
        Mp[i] = mx > i?min(Mp[2 * d - i], mx - i):1;
        while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
        if(i + Mp[i] > mx) {
            mx = Mp[i] + i;
            d = i;
        }
    }

    mx = 0;
    rep(i, 0, l - 1) mx = max(mx, Mp[i] - 1);
    return mx;
}

char s[N];
int ls;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%s", s) && s[0] != 'E') {
        ls = strlen(s);
        printf("Case %d: %d\n", Case++, manacher(s, ls));
    }

    return 0;
}

吉哥又想出了一個新的完美隊形遊戲!    假設有n個人按順序站在他的面前,他們的身高分別是h[1], h[2] ... h[n],吉哥希望從中挑出一些人,讓這些人形成一個新的隊形,新的隊形若滿足以下三點要求,則就是新的完美隊形:    1、挑出的人保持原隊形的相對順序不變,且必須都是在原隊形中連續的;    2、左右對稱,假設有m個人形成新的隊形,則第1個人和第m個人身高相同,第2個人和第m-1個人身高相同,依此類推,當然如果m是奇數,中間那個人可以任意;    3、從左到中間那個人,身高需保證不下降,如果用H表示新隊形的高度,則H[1] <= H[2] <= H[3] .... <= H[mid]。    現在吉哥想知道:最多能選出多少人組成新的完美隊形呢?

Input

  輸入資料第一行包含一個整數T,表示總共有T組測試資料(T <= 20);    每組資料首先是一個整數n(1 <= n <= 100000),表示原先隊形的人數,接下來一行輸入n個整數,表示原隊形從左到右站的人的身高(50 <= h <= 250,不排除特別矮小和高大的)。

Output

  請輸出能組成完美隊形的最多人數,每組輸出佔一行。

Sample Input

2
3
51 52 51
4
51 52 52 51

Sample Output

3
4

沒看到要求在原串中連續,自閉了好一會兒一百度發現提讀錯了。。

在馬拉車裡改一下匹配條件就行了。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
int Case = 1;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int Ma[N * 2];
int Mp[N * 2];

int manacher(int *s, int ls)
{
    int l = 0;
    Ma[l++] = '@';
    Ma[l++] = '#';
    for(int i = 0; i< ls; i++) {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = '\0';
    int mx = 0, d = 0;
    for(int i = 0; i < l; i++) {
        Mp[i] = mx > i?min(Mp[2 * d - i], mx - i):1;
        while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) {
            if(Ma[i + Mp[i]] != '#') {
                if(Ma[i + Mp[i]] <= Ma[i + Mp[i] - 2]) Mp[i]++;
                else break;
            }
            Mp[i]++;
        }
        if(i + Mp[i] > mx) {
            mx = Mp[i] + i;
            d = i;
        }
    }

    mx = 0;
    rep(i, 0, l - 1) mx = max(mx, Mp[i] - 1);
    return mx;
}

int s[N];
int ls;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &ls);
        rep(i, 0, ls - 1) scanf("%d", &s[i]);
        printf("%d\n", manacher(s, ls));
    }

    return 0;
}

One day, sailormoon girls are so delighted that they intend to research about palindromic strings. Operation contains two steps:  First step: girls will write a long string (only contains lower case) on the paper. For example, "abcde", but 'a' inside is not the real 'a', that means if we define the 'b' is the real 'a', then we can infer that 'c' is the real 'b', 'd' is the real 'c' ……, 'a' is the real 'z'. According to this, string "abcde" changes to "bcdef". Second step: girls will find out the longest palindromic string in the given string, the length of palindromic string must be equal or more than 2.

Input

Input contains multiple cases.  Each case contains two parts, a character and a string, they are separated by one space, the character representing the real 'a' is and the length of the string will not exceed 200000.All input must be lowercase.  If the length of string is len, it is marked from 0 to len-1.

Output

Please execute the operation following the two steps.  If you find one, output the start position and end position of palindromic string in a line, next line output the real palindromic string, or output "No solution!".  If there are several answers available, please choose the string which first appears.

Sample Input

b babd
a abcd

Sample Output

0 2
aza
No solution!

把串改造一下找回文。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
int Case = 1;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

char Ma[N * 2];
int Mp[N * 2];

void manacher(char *s, int ls)
{
    int l = 0;
    Ma[l++] = '@';
    Ma[l++] = '#';
    for(int i = 0; i< ls; i++) {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = '\0';
    int mx = 0, d = 0;
    for(int i = 0; i < l; i++) {
        Mp[i] = mx > i?min(Mp[2 * d - i], mx - i):1;
        while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) {
//            if(Ma[i + Mp[i]] != '#') {
//                if(Ma[i + Mp[i]] <= Ma[i + Mp[i] - 2]) Mp[i]++;
//                else break;
//            }
            Mp[i]++;
        }
        if(i + Mp[i] > mx) {
            mx = Mp[i] + i;
            d = i;
        }
    }

    mx = 0;
    int p = 0;
    rep(i, 0, l - 1) {
        if(mx < Mp[i] - 1) {
            p = i;
            mx = Mp[i] - 1;
        }
    }
    if(mx == 1) {
        puts("No solution!");
        return;
    }
    printf("%d %d\n", (p - mx + 1) / 2 - 1, (p + mx) / 2 - 1);
    for(int i = p - mx + 1; i < p + mx; i += 2) putchar(Ma[i]);
    putchar('\n');
}

char s[N], ch;
int ls;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(cin >> ch) {
        scanf("%s", s);
        ls = strlen(s);

        int d = 'a' - ch;
        rep(i, 0, ls - 1) s[i] = 'a' + ((s[i] - 'a' + d + 26) % 26);
    //cout << s << endl;
        manacher(s, ls);
    }

    return 0;
}

給出一個只由小寫英文字元a,b,c...y,z組成的字串S,求S中最長迴文串的長度.  迴文就是正反讀都是一樣的字串,如aba, abba等

Input

輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b,c...y,z組成的字串S  兩組case之間由空行隔開(該空行不用處理)  字串長度len <= 110000

Output

每一行一個整數x,對應一組case,表示該組case的字串中所包含的最長迴文長度. 

Sample Input

aaaa

abab

Sample Output

4
3

板子題

Chen, Adrian (November 7, 2013). “Doge Is An Ac- tually Good Internet Meme. Wow.”. Gawker. Retrieved November 22, 2013.  Doge is an Internet meme that became popular in 2013. The meme typically con- sists of a picture of a Shiba Inu dog ac- companied by multicolored text in Comic Sans MS font in the foreground. The text, representing a kind of internal monologue, is deliberately written in broken English, and usually contains the word “wow” and the phrases “such x”, “much x”, “many x”, “very x” and “so x”.  Kabosu, the Shiba Inu featured in the original meme, was first pictured in a 2010 blog post by Atsuko Sato, a Japanese kindergarten teacher. Afterwards, varia- tions of the pictures using overlaid Comic Sans text were posted from a Tumblr blog, Shiba Confessions. However, the use of the intentionally misspelled “doge” dates back to June 2005, when it was mentioned in an episode of Homestar Runners puppet series.  In August 2013, images of the meme were spammed on Reddit’s r/MURICA subreddit by 4chan’s random imageboard, /b/. A search of the term doge on Google Trends shows an explosion of popularity occurring in October 2013, and more so in the following month. By November 2013, the meme had become widespread on the Internet. Google later created a Doge Easter egg: when doge meme was entered into the YouTube search bar, all of the site’s text would be displayed in colorful Comic Sans, similar to the kind used by the meme.  The meme was ranked #12 on MTV’s list of “50 Things Pop Culture Had Us Giving Thanks For” in 2013. Io9 compared the internal dialog of the Shiba Inu dogs to lolcat-speak. The image most commonly associated with the meme is of a female Shiba Inu named Kabosu, taken from a Japanese blog documenting the dog’s daily activities. The spelling of doge has several variants, leading to debate on its actual pronunciation. On December 13, Doge was named the “top meme” of 2013 by Know Your Meme.  In December 2013, the Dogecoin was introduced as a new cryptocurrency, making it the first cryptocurrency to be based on an Internet meme; the viral phenomenon, along with usage of the Comic Sans MS typeface, gave it “the Internet density of a large star” according to Medium writer Quinn Norton.  In late December 2013, members of the U.S. Congress produced material in the meme’s style. Huffington Post commented that Doge was “killed” because of the Congress members’ usage of the meme.  By early 2014, Doge’s popularity was sustained by internet communities on social media, accompanied by the rapid growth and acceptance of Dogecoin. In April 2014, Doge experienced a second major media resurgence due to revelations of the Dogecoin community’s intent to sponsor Josh Wise in NASCAR and place a picture of the Shiba Inu on his vehicle.  —— Doge (meme). (2014, May 18).  In Wikipedia, The Free Encyclopedia. Retrieved 02:00, May 22, 2014, from  http://en.wikipedia.org/w/index.php?title=Doge_(meme)&oldid=609040691  Now, Doge wants to know how many words “doge” are there in a given article. Would you like to help Doge solve this problem?

Input

An article that Doge wants to know.  The size of the article does not exceed 64KB. The article contains only ASCII characters.

Output

Please output the number of word “doge” (case- insensitive). Refer to the samples for more details.

Sample Input

adoge
cutedo 
yourge 
blownDoge
lovelyDooge
Wow!	Such Dooooooooooooooge!!!
D0ge
dOge DOGE 
dogedoge

Sample Output

6

把串改造一下kmp。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
int Case = 1;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int nxt[10];
void getnxt(char *s, int ls)
{
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < ls;) {
        if(k == -1 || s[i] == s[k]) nxt[++i] = ++k;
        else k = nxt[k];
    }
}
int kmp(char *s, int ls, char *p, int lp)
{
    int k = 0;
    int ans = 0;
    for(int i = 0; i < ls;) {
        if(k == -1 || s[i] == p[k]) {
            ++i; ++k;
        }
        else k = nxt[k];
        if(k == lp) {
            k  = 0;
            ans++;
        }
    }
    return ans;
}

char s[N];
int ls, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    char t[] = "doge";
    getnxt(t, 4);

    cnt = 0;
    while(~scanf("%s", s)) {
        ls = strlen(s);
        rep(i, 0, ls - 1) {
            if(isupper(s[i])) {
                s[i] = s[i] - 'A' + 'a';
            }
        }
        cnt += kmp(s, ls, t, 4);
    }
    printf("%d\n", cnt);

    return 0;
}

It's time for music! A lot of popular musicians are invited to join us in the music festival. Each of them will play one of their representative songs. To make the programs more interesting and challenging, the hosts are going to add some constraints to the rhythm of the songs, i.e., each song is required to have a 'theme section'. The theme section shall be played at the beginning, the middle, and the end of each song. More specifically, given a theme section E, the song will be in the format of 'EAEBE', where section A and section B could have arbitrary number of notes. Note that there are 26 types of notes, denoted by lower case letters 'a' - 'z'.  To get well prepared for the festival, the hosts want to know the maximum possible length of the theme section of each song. Can you help us? 

Input

The integer N in the first line denotes the total number of songs in the festival. Each of the following N lines consists of one string, indicating the notes of the i-th (1 <= i <= N) song. The length of the string will not exceed 10^6.

Output

There will be N lines in the output, where the i-th line denotes the maximum possible length of the theme section of the i-th song. 

Sample Input

5
xy
abc
aaa
aaaaba
aaxoaaaaa

Sample Output

0
0
1
1
2

先用擴充套件kmp找出首尾相同的,然後用kmp到找見去找。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 1000010
#define M 20010
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
int Case = 1;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
#define rrep(i, lll, nnn) for(int i = (lll); i >= (nnn); i--)

int nxt[N];
void getnxt(char *s, int ls)
{
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < ls;) {
        if(k == -1 || s[i] == s[k]) nxt[++i] = ++k;
        else k = nxt[k];
    }
}
bool kmp(char *s, int ls, char *p, int lp)
{//cout  << s << ' ' << p << endl;
    getnxt(p, lp);
    int k = 0;
    for(int i = 0; i < ls;) {
        if(k == -1 || s[i] == p[k]) {
            ++i; ++k;
        }
        else k = nxt[k];
        if(k == lp) return true;
    }
    return false;
}

int net[N], ext[N];
void getexnxt(char *s, int ls)
{
    net[0] = ls;
    int j = 0;
    while(j + 1 < ls && s[j] == s[j + 1]) j++;
    net[1] = j;
    int k = 1;
    for(int i = 2; i < ls; i++) {
        int p = net[k] + k - 1;
        int l = net[i - k];
        if(i + l < p + 1) net[i] = l;
        else {
            j = max(0, p - i + 1);
            while(i + j < ls && s[j] == s[i + j]) j++;
            k = i;
            net[i] = j;
        }
    }
}
void exkmp(char *s, int ls, char *t, int lt)
{
    getexnxt(t, lt);
//rep(i, 0, lt - 1) cout << "net " << net[i] << endl;
    int j = 0;
    while(j < ls && j < lt && s[j] == t[j]) j++;
    ext[0] = j;
    int k = 0;
    for(int i = 1; i < ls; i++) {
        int p = ext[k] + k - 1;
        int l = net[i - k];
        if(i + l < p + 1) ext[i] = l;
        else {
            j = max(0, p - i + 1);
            while(i + j < ls && s[i + j] == t[i]) j++;
            k = i;
            ext[i] = j;
        }
    }
}

char s[N], t[N], tmp[N];
int ls, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int T;
    scanf("%d", &T);

    while(T--) {
        scanf("%s", s);
        ls = strlen(s);
        if(ls < 3) {
            puts("0");
            continue;
        }
        strcpy(t, s);
        exkmp(s, ls, t, ls);

        bool flag = false;
        for(int i = (ls / 3) * 2; i < ls; i++) if(ext[i] + i == ls){
            int len = ext[i];
            if(len * 3 > ls) continue;
//rep(i, 0, ls - 1) cout << "ext " << ext[i] << endl;
            if(len == 0) break;
            else {
                rep(j, len, ls - len - 1) tmp[j - len] = s[j];
                tmp[ls - 2 * len] = '\0';
                if(kmp(tmp, ls - 2 * len, s + ls - len, len)) {
                    printf("%d\n", len);
                    flag = true;
                    break;
                }
            }
        }
        if(!flag) puts("0");
    }

    return 0;
}