Kuangbin专题十六KMP & 扩展KMP & Manacher(A~L)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40379678/article/details/82901996

 

A - Number Sequence

 HDU - 1711

Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], ...... , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one. 

Input

The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], ...... , a[N]. The third line contains M integers which indicate b[1], b[2], ...... , b[M]. All integers are in the range of [-1000000, 1000000]. 

Output

For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead. 

Sample Input

2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1

Sample Output

6
-1

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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

int nxt[N];
void getnext(int * s, int n)
{
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < n; ) {
        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 kmp(int * a, int * b, int n, int m)
{
    int k = 0;
    for(int i = 0; i < n; ) {
        if(k == -1 || a[i] == b[k]) {
            i++; k++;
        }
        else k = nxt[k];
//cout << "k " << k << endl;
        if(k == m) return i - m + 1;
    }
    return -1;
}

int a[N], b[N], n, m;

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

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

    while(t--) {
        scanf("%d%d", &n, &m);
        rep(i, 0, n - 1) scanf("%d", &a[i]);
        rep(i, 0, m - 1) scanf("%d", &b[i]);
        getnext(b, m);
//rep(i, 0, m - 1) printf("%d ", nxt[i]);puts("");
        printf("%d\n", kmp(a, b, n, m));
    }

    return 0;
}


B - Oulipo

 HDU - 1686

The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book: 

Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais… 

Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive 'T's is not unusual. And they never use spaces. 

So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {'A', 'B', 'C', …, 'Z'} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap. 
 

Input

The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format: 

One line with the word W, a string over {'A', 'B', 'C', …, 'Z'}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W). 
One line with the text T, a string over {'A', 'B', 'C', …, 'Z'}, with |W| ≤ |T| ≤ 1,000,000. 

Output

For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T. 
 

Sample Input

3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN

Sample Output

1
3
0

数a串在b串中的数量,kmp板子题。

a串在b中可重复,所以匹配到一个后回溯是k = nxt[k]。

#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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

int nxt[N];
void getnext(char * s, int n)
{
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < n; ) {
        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 kmp(char * a, char * b, int n, int m)
{
    int k = 0, cnt = 0;
    for(int i = 0; i < n; ) {
        if(k == -1 || a[i] == b[k]) {
            i++; k++;
        }
        else k = nxt[k];
//cout << "k " << k <<endl;
        if(k == m) {
            cnt++; k = nxt[k];
        }
    }
    return cnt;
}

char a[N], b[N];
int n, m;

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

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

    while(t--) {
        scanf("%s%s", b, a);
        n = strlen(a); m = strlen(b);
        getnext(b, m);
   // rep(i, 0, m) printf("%d ", nxt[i]); puts("");
        printf("%d\n", kmp(a, b, n, m));
    }

    return 0;
}


C - 剪花布条

 HDU - 2087

一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? 

Input

输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。 

Output

输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。 

Sample Input

abcde a3
aaaaaa  aa
#

Sample Output

0
3

数a串在b串中的数量,kmp板子题。

a串在b中不可重复,所以匹配到一个后回溯是k = 0。

#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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

int nxt[N];
void getnext(char * s, int n)
{
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < n; ) {
        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 kmp(char * a, char * b, int n, int m)
{
    int k = 0, cnt = 0;
    for(int i = 0; i < n; ) {
        if(k == -1 || a[i] == b[k]) {
            i++; k++;
        }
        else k = nxt[k];
//cout << "k " << k <<endl;
        if(k == m) {
            cnt++; k = 0;
        }
    }
    return cnt;
}

char a[N], b[N];
int n, m;

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

    while(true) {
        scanf("%s", a);
        if(a[0] == '#') break;
        scanf("%s", b);
        n = strlen(a); m = strlen(b);
        getnext(b, m);
   // rep(i, 0, m) printf("%d ", nxt[i]); puts("");
        printf("%d\n", kmp(a, b, n, m));
    }

    return 0;
}

 

D - Cyclic Nacklace

 HDU - 3746

CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of "HDU CakeMan", he wants to sell some little things to make money. Of course, this is not an easy task. 

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl's fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls' lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet's cycle is 9 and its cyclic count is 2: 


Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden. 
CC is satisfied with his ideas and ask you for help.

Input

The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases. 
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by 'a' ~'z' characters. The length of the string Len: ( 3 <= Len <= 100000 ).

Output

For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.

Sample Input

3
aaa
abca
abcde

Sample Output

0
2
5

给一个串,求最少加多少字符使其为周期串。

当它本来就是周期串时输出0,否则最后一段就是周期的一部分,输出该补的长度就行。

比如abcabcabc是周期串输出0,而abcabca最后的a是循环节abc的一部分,该补上bc的长度2。

判断周期串是:int len = ls - nxt[ls]; len != ls && ls % len == 0这两句,当len是ls的因子时就是周期串。
如果不是周期串,那么len的串是最小循环节的一部分,len - nxt[ls] % len是减去已经匹配的部分。

#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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

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

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

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

    while(t--) {
        scanf("%s", s);
        ls = strlen(s);
        getnext(s, ls);
        int len = ls - nxt[ls];
        if(len != ls && ls % len == 0) puts("0");
        else printf("%d\n", len - nxt[ls] % len);
    }

    return 0;
}


E - Period

 HDU - 1358

For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K , that is A concatenated K times, for some string A. Of course, we also want to know the period K. 

Input

The input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it. 

Output

For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case. 

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

int n;
char s[N];

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

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

    int Case = 1;
    while(scanf("%d", &n) && n) {
        scanf("%s", s);
        getnxt(s, n);
        printf("Test case #%d\n", Case++);
        rep(i, 1, n) {
            if(nxt[i] <= 0) continue;
            int len = i - nxt[i];
            if(i % len == 0) printf("%d %d\n", i, i / len);
        }
        puts("");
    }

    return 0;
}

F - The Minimum Length

 HUST - 1010

There is a string A. The length of A is less than 1,000,000. I rewrite it again and again. Then I got a new string: AAAAAA...... Now I cut it from two different position and get a new string B. Then, give you the string B, can you tell me the length of the shortest possible string A. 
For example, A="abcdefg". I got abcd efgabcdefgabcdefgabcdefg.... Then I cut the red part: efgabcdefgabcde as string B. From B, you should find out the shortest A. 
 

Input

Multiply Test Cases. 
For each line there is a string B which contains only lowercase and uppercase charactors. 
The length of B is no more than 1,000,000. 

Output

For each line, output an integer, as described above.

Sample Input

bcabcab
efgabcdefgabcde

Sample Output

3
7

给你串求将其补成周期串的最小循环节长度。

如果B是周期串,显然ls - nxt[ls]

如果不是那么ls - nxt[ls]就是该串把尾巴多的非周期部分去掉,得到最小循环节。

#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 1000010
#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++)

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

char s[N];
int ls;

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

    while(~scanf("%s", s)) {
        ls = strlen(s);
        getnxt(s, ls);
        if(ls == 1) puts("1");
        else printf("%d\n", ls - nxt[ls]);
    }

    return 0;
}

G - Power Strings

 POJ - 2406

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.

最小循环节周期串。

#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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

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

char s[N];
int ls;

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

    while(scanf("%s", s) && s[0] != '.') {
        ls = strlen(s);
        getnxt(s, ls);
        if(ls % (ls - nxt[ls])) puts("1");
        else printf("%d\n", ls / (ls - nxt[ls]));
    }

    return 0;
}

H - Seek the Name, Seek the Fame

 POJ - 2752

The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm: 

Step1. Connect the father's name and the mother's name, to a new string S. 
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S). 

Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:) 

Input

The input contains a number of test cases. Each test case occupies a single line that contains the string S described above. 

Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000. 

Output

For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.

Sample Input

ababcababababcabab
aaaaa

Sample Output

2 4 9 18
1 2 3 4 5

求前缀等于后缀的子串。nxt数组的意义就是前缀等于后缀的长度,所以p指针直接移到nxt[p],nxt[p]~p之间是不可能有答案的,因为如果p是匹配中的一元,那么肯定nxt[p]>=p,矛盾。

#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<double, double> P;
typedef long long ll;
#define N 1000010
#define M 2000100
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++)

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

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

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

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

    return 0;
}

I - Blue Jeans

 POJ - 3080 

The Genographic Project is a research partnership between IBM and The National Geographic Society that is analyzing DNA from hundreds of thousands of contributors to map how the Earth was populated. 

As an IBM researcher, you have been tasked with writing a program that will find commonalities amongst given snippets of DNA that can be correlated with individual survey information to identify new genetic markers. 

A DNA base sequence is noted by listing the nitrogen bases in the order in which they are found in the molecule. There are four bases: adenine (A), thymine (T), guanine (G), and cytosine (C). A 6-base DNA sequence could be represented as TAGACC.

Given a set of DNA base sequences, determine the longest series of bases that occurs in all of the sequences.

Input

Input to this problem will begin with a line containing a single integer n indicating the number of datasets. Each dataset consists of the following components:

  • A single positive integer m (2 <= m <= 10) indicating the number of base sequences in this dataset.
  • m lines each containing a single base sequence consisting of 60 bases.

Output

For each dataset in the input, output the longest base subsequence common to all of the given base sequences. If the longest common subsequence is less than three bases in length, display the string "no significant commonalities" instead. If multiple subsequences of the same longest length exist, output only the subsequence that comes first in alphabetical order.

Sample Input

3
2
GATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
3
GATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATACCAGATA
GATACTAGATACTAGATACTAGATACTAAAGGAAAGGGAAAAGGGGAAAAAGGGGGAAAA
GATACCAGATACCAGATACCAGATACCAAAGGAAAGGGAAAAGGGGAAAAAGGGGGAAAA
3
CATCATCATCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
ACATCATCATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACATCATCATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

Sample Output

no significant commonalities
AGATAC
CATCATCAT

emmmmmmmmmmmmm暴力枚举一个串的子串来匹配

#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<double, double> P;
typedef long long ll;
#define N 100
#define M 2000100
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++)

int nxt[N];
void getnxt(char * s, int n)
{
    int k = -1;  nxt[0] = -1;
    for(int i = 0; i < n; ) {
        if(k == -1 || s[i] == s[k]) nxt[++i] = ++k;
        else k = nxt[k];
    }
}
bool kmp(char * a, char * b, int la, int lb)
{
// int la = strlen(a), lb = strlen(b);
    getnxt(b, lb);
//cout << a << endl;
    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;
}

char s[15][100];
char sub[100], ans[100];
int lans;
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    int t, m;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &m);
        rep(i, 1, m) scanf("%s", s[i]);
        rep(i, 0, 60) ans[i] = 'z'; ans[61] = '\0';
        lans = 0;
//cout << s[1] <<endl;
        for(int l = 60; l >= 3; l--) {//cout <<l << endl;
            for(int i = 0; i + l <= 60; i++) {
                for(int j = i; j < l + i; j++) sub[j - i] = s[1][j];
                sub[l + i] = '\0';
//cout << sub <<endl;
                bool flag = true;
                for(int j = 2; j <= m; j++) {
                    if(!kmp(s[j], sub, 60, l)) {
                        flag = false; break;
                    }
                }
                if(flag) {
           // cout << sub << ' ' << lans << ' '<< endl;
                    if(lans < l) strcpy(ans, sub), lans = l;
                    else if(lans == l && strcmp(ans, sub) > 0)
                        strcpy(ans, sub);
                }
            }
            if(lans > 0) {
                printf("%s\n", ans);
                break;
            }
        }
        if(!lans) puts("no significant commonalities");
    }

    return 0;
}

J - Simpsons’ Hidden Talents

 HDU - 2594

Homer: Marge, I just figured out a way to discover some of the talents we weren’t aware we had. 
Marge: Yeah, what is it? 
Homer: Take me for example. I want to find out if I have a talent in politics, OK? 
Marge: OK. 
Homer: So I take some politician’s name, say Clinton, and try to find the length of the longest prefix 
in Clinton’s name that is a suffix in my name. That’s how close I am to being a politician like Clinton 
Marge: Why on earth choose the longest prefix that is a suffix??? 
Homer: Well, our talents are deeply hidden within ourselves, Marge. 
Marge: So how close are you? 
Homer: 0! 
Marge: I’m not surprised. 
Homer: But you know, you must have some real math talent hidden deep in you. 
Marge: How come? 
Homer: Riemann and Marjorie gives 3!!! 
Marge: Who the heck is Riemann? 
Homer: Never mind. 
Write a program that, when given strings s1 and s2, finds the longest prefix of s1 that is a suffix of s2.

Input

Input consists of two lines. The first line contains s1 and the second line contains s2. You may assume all letters are in lowercase.

Output

Output consists of a single line that contains the longest string that is a prefix of s1 and a suffix of s2, followed by the length of that prefix. If the longest such string is the empty string, then the output should be 0. 
The lengths of s1 and s2 will be at most 50000.

Sample Input

clinton
homer
riemann
marjorie

Sample Output

0
rie 3

输出两个串的前缀后缀。

#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 100010
#define M 2000100
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++)

string a, b, c;
int nxt[N];

void getnxt()
{
    int n = c.length();
    nxt[0] = -1;
    int k = -1;
    for(int i = 0; i < n; ) {
        if(k == -1 || c[i] == c[k]) nxt[++i] = ++k;
        else k = nxt[k];
    }
}

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

    while(cin >> a >> b) {
        c = a + b;
        getnxt();
        if(nxt[c.length()] == 0) puts("0");
        else {
            int i = 0;
            for(i = 0; i < nxt[c.length()] && i < a.length() && i < b.length(); i++) putchar(c[i]);
            printf(" %d\n", i);
        }
    }

    return 0;
}

K - Count the string

 HDU - 3336 

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example: 
s: "abab" 
The prefixes are: "a", "ab", "aba", "abab" 
For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6. 
The answer may be very large, so output the answer mod 10007. 

Input

The first line is a single integer T, indicating the number of test cases. 
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters. 

Output

For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample Input

1
4
abab

Sample Output

6

大难题啊啊啊啊啊我死了,百度下来是分段加emmmmm。

当nxt[i] + 1 != nxt[i + 1]时,说明i+1位置失配了,所以nxt[i]就是i-nxt[i]到i这段串的长度nxt[i]就是与之匹配的原串的前缀长度,而前缀长度就是前缀串的个数Orz,也就是在i-nxt[i]到i这段串的贡献。

#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<double, double> P;
typedef long long ll;
#define N 200010
#define M 2000100
const int INF = 0x3f3f3f3f;
const int mod = 10007;
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++)

int n, ans;
char s[N];

int nxt[N];
void getnxt(char * s, int n)
{
    nxt[n + 1] = INF;
    int k = -1; nxt[0] = -1;
    for(int i = 0; i < n; ) {
        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);
    while(t--) {
        scanf("%d%s", &n, s);
        getnxt(s, n);
//rep(i, 1, n) printf("%d ", nxt[i]);
        ans = n;
        rep(i, 2, n) if(nxt[i] + 1 != nxt[i + 1]) {
            ans += nxt[i];
            ans %= mod;
        }
        printf("%d\n", ans);
    }

    return 0;
}

L - Clairewd’s message

 HDU - 4300

Clairewd is a member of FBI. After several years concealing in BUPT, she intercepted some important messages and she was preparing for sending it to ykwd. They had agreed that each letter of these messages would be transfered to another one according to a conversion table. 
Unfortunately, GFW(someone's name, not what you just think about) has detected their action. He also got their conversion table by some unknown methods before. Clairewd was so clever and vigilant that when she realized that somebody was monitoring their action, she just stopped transmitting messages. 
But GFW knows that Clairewd would always firstly send the ciphertext and then plaintext(Note that they won't overlap each other). But he doesn't know how to separate the text because he has no idea about the whole message. However, he thinks that recovering the shortest possible text is not a hard task for you. 
Now GFW will give you the intercepted text and the conversion table. You should help him work out this problem. 

Input

The first line contains only one integer T, which is the number of test cases. 
Each test case contains two lines. The first line of each test case is the conversion table S. S[i] is the ith latin letter's cryptographic letter. The second line is the intercepted text which has n letters that you should recover. It is possible that the text is complete. 

Hint

Range of test data: 
T<= 100 ; 
n<= 100000; 

Output

For each test case, output one line contains the shorest possible complete text.

Sample Input

2
abcdefghijklmnopqrstuvwxyz
abcdab
qwertyuiopasdfghjklzxcvbnm
qwertabcde

Sample Output

abcdabcd
qwertabcde

这题题意贼难理解。其实是给一个串,这个串前部分是密文,后部分是明文(可能空),但是明文不全,要你求原文长啥样。加密方法也给你。 其实是把串翻译一下,正着反着翻译我觉得都行,那就把给的串按加密方式加密一遍,那么加密得到的串就会和原串有前缀后缀相等的关系,然后扩展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 200010
#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++)

char tab[30], s[N], t[N];
int ls;
map<char, char> mp;

int nxt[N], ext[N];
void getnxt(char * x, int m)
{
    nxt[0] = m;
    int j = 0;
    while(j + 1 < m && x[j] == x[j + 1]) j++;
    nxt[1] = j;
    int k = 1;
    for(int i = 2; i < m; i++) {
        int p = nxt[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < p + 1) nxt[i] = L;
        else {
            j = max(0, p - i + 1);
            while(i + j < m && x[i + j] == x[j]) j++;
            nxt[i] = j;
            k = i;
        }
    }
}
void exkmp(char * x, int m, char * y, int n)
{
    //memset(nxt, 0, sizeof nxt);
    //memset(ext, 0, sizeof ext);
    getnxt(x, m);
//cout << x << ' ';
//rep(i, 0, m) cout << nxt[i] << ' '; cout << endl;
    int j = 0;
    while(j < n && j < m && x[j] == y[j]) j++;
    ext[0] = j;
    int k = 0;
    for(int i = 1; i < n; i++) {
        int p = ext[k] + k - 1;
        int L = nxt[i - k];
        if(i + L < p + 1) ext[i] = L;
        else {
            j = max(0, p - i + 1);
            while(j + i < n && j < m && y[i + j] == x[j]) j++;
            ext[i] = j;
            k = i;
        }
      //  cout << k << ' ' << p << ' ' << L << ' ' << ext[i] << endl;
    }
}

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

    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%s%s", tab, s);
        ls = strlen(s);

        mp.clear();
        for(int i = 0; tab[i]; i++) mp[tab[i]] = char(i + 'a');

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

        exkmp(t, ls, s, ls);
//rep(i, 0, ls) cout << ext[i] << ' '; cout << endl;
        int i;
        for(i = 0; i < ls; i++) {
            if(ext[i] + i >= ls && i >= ext[i]) {
                break;
            }
        }
        for(int j = 0; j < i; j++) putchar(s[j]);
        for(int j = 0; j < i; j++) putchar(mp[s[j]]);

        putchar('\n');
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40379678/article/details/82901996