(2019.9.5~2019.9.11)补题汇总(字符串相关)

[1] [HDU3374]String Problem

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5489 Accepted Submission(s): 2258

Problem Description

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

解题思路

挺综合的一道题(我还是太菜了2333)。需要求循环字符串中字典序最小和最大的并输出其出现的次数。求字符串用到最大最小表示法(图示更新中ing......),统计出现次数正好可以用到KMP中记录next(prefix)数组。刚开始用的是纯模拟优化了一下直接wa了。。。。。。后来不读一下全是班子,emm......

代码样例(转自ChenJr

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2000005;

char s[maxn];
int nextt[maxn];

void get_next(char *a, int len)
{ //求解next数组板子
    int i = 0, j = nextt[0] = -1;
    while (i < len)
    {
        while (j != -1 && a[i] != a[j])
            j = nextt[j];
        nextt[++i] = ++j;
    }
}

int get_minn(char *a, int len)
{ //最小表示法板子
    int i = 0, j = 1;
    for (int i = 0; i < len; i++)
    {
        s[i + len] = s[i];
    }
    while (i < len && j < len)
    {
        int k;
        for (k = 0; k < len && a[k + i] == a[k + j]; k++)
            ;
        if (k == len)
            break;
        if (a[k + i] > a[k + j])
        {
            i = i + k + 1;
            if (i == j)
                i++;
        }
        else
        {
            j = j + k + 1;
            if (i == j)
                j++;
        }
    }
    return min(i, j);
}

int get_maxx(char *a, int len)
{ //最大表示法板子
    int i = 0, j = 1;
    for (int i = 0; i < len; i++)
    {
        s[i + len] = s[i];
    }
    while (i < len && j < len)
    {
        int k;
        for (k = 0; k < len && a[k + i] == a[k + j]; k++)
            ;
        if (k == len)
            break;
        if (a[k + i] < a[k + j])
        {
            i = i + k + 1;
            if (i == j)
                i++;
        }
        else
        {
            j = j + k + 1;
            if (i == j)
                j++;
        }
    }
    return min(i, j);
}

int main()
{
    while (~scanf("%s", s))
    {
        int len = strlen(s);
        memset(nextt, 0, sizeof(nextt));
        get_next(s, len);
        int minn = get_minn(s, len);
        int maxx = get_maxx(s, len);
        int tmp = nextt[len];
        if (len % (len - tmp) != 0)
        {
            cout << minn + 1 << " 1 " << maxx + 1 << " 1" << endl;
        }
        else
        {
            cout << minn + 1 << " " << len / (len - tmp) << " " << maxx + 1 << " " << len / (len - tmp) << endl;
        }
    }
    return 0;
}

[2] [HDU-6229]string matching

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1708 Accepted Submission(s): 706

Problem Description

String matching is a common type of problem in computer science. One string matching problem is as following:

Given a string s[0…len−1], please calculate the length of the longest common prefix of s[i…len−1] and s[0…len−1] for each i>0.

I believe everyone can do it by brute force.
The pseudo code of the brute force approach is as the following:

img

We are wondering, for any given string, what is the number of compare operations invoked if we use the above algorithm. Please tell us the answer before we attempt to run this algorithm.

Input

The first line contains an integer T, denoting the number of test cases.
Each test case contains one string in a line consisting of printable ASCII characters except space.

* 1≤T≤30

* string length ≤106 for every string

Output

For each test, print an integer in one line indicating the number of compare operations invoked if we run the algorithm in the statement against the input string.

Sample Input

3
_Happy_New_Year_
ywwyww
zjczzzjczjczzzjc

Sample Output

17
7
32

解题思路

扩展KMP,一开始以为是ac自动机,结果gg。利用扩展KMP求出每一位的最长字符子串,如果这一位的位置加上它的子串长没用超过字符串的最后一位,在统计时还要加上一次比较次数。

*扩展KMP参考拓展kmp算法总结

代码样例

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int K=1000005;
int nt[K],extand[K];
char S[K],T[K];
int a[K];
ll ans;

void Getnext(char *T,int *next)
{
    int len=strlen(T),a=0;
    next[0]=len;
    while(a<len-1 && T[a]==T[a+1]) a++;
    next[1]=a;
    a=1;
    for(int k=2; k<len; k++)
    {
        int p=a+next[a]-1,L=next[k-a];
        if( (k-1)+L >= p)
        {
            int j = (p-k+1)>0 ? (p-k+1) : 0;
            while(k+j<len && T[k+j]==T[j]) j++;
            next[k]=j;
            a=k;
        }
        else
            next[k]=L;
    }
}

void GetExtand(char *S,char *T,int *next)
{
    Getnext(T,next);
    int slen=strlen(S),tlen=strlen(T),a=0;
    int MinLen = slen < tlen ? slen : tlen;
    while(a<MinLen && S[a]==T[a]) a++;
    extand[0]=a;
    a=0;
    for(int k=1; k<slen; k++)
    {
        int p=a+extand[a]-1, L=next[k-a];
        if( (k-1)+L >= p)
        {
            int j= (p-k+1) > 0 ? (p-k+1) : 0;
            while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;
            extand[k]=j;
            a=k;
        }
        else
            extand[k]=L;
    }
}

int main(void)
{
	int tl;scanf("%lld",&tl);
    while(tl--)
    {
    	memset(nt,0,sizeof(nt));
    	memset(extand,0,sizeof(extand));
    	memset(a,0,sizeof(a));
		scanf("%s",S);
    	ans = 0;
    	strcpy(T,S);
        GetExtand(S,T,nt);
        int len = strlen(T);
        queue<int> id;
		ans = 0;
		ans+=len-1;
		for(int i=1; i<len; i++) {
			if(nt[i]!=0) {
				ans+=nt[i];
				if(i+nt[i]>=len)ans--;
			}
		}
		printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cafu-chino/p/11759923.html