您的位置:首页 > 其它

HDU 5442 KMP + 最小表示法

2015-09-17 19:22 274 查看
HDU 5442

题目链接:

题意:

一个字符串里,从任意起点出发顺时针或者逆时针遍历字符串得到一个新的字符串。问得到的字典序最大的字符串。

存在多个相同的字符串时,输出起点最小的;起点相同时,优先输出顺时针。

思路:

最小表示法 + KMP。

顺时针,直接用最小表示法得到答案。

逆时针,把串翻转。先用最小表示法得到最大字典序的字符串A,再用KMP得到离起点最远的点匹配A。

然后就完了。





最小表示法,O(n)。开两个指针,具体网上有证明。



KMP。有fail表示长度和序号的两种写法,注意不要搞混。

源码:

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <string>

#include <queue>

using namespace std;

const int MAXN = 20000 * 2 + 5;

char str1[MAXN], str2[MAXN];

char P[MAXN], T[MAXN];

int Minpre(char *s, int len)

{

int i, j, k;

i = 0;

j = 1;

while(i < len && j < len){

for(k = 0 ; k < len ; k++) if(s[(k + i) % len] != s[(k + j) % len]) break;

if(k == len) break;

if(s[(k + i) % len] > s[(k + j) % len]) i = k + i + 1;

else j = k + j + 1;

if(i == j) j++;

}

return min(i, j);

}

int fail[MAXN];

void failure(char *s, int len)

{

fail[0] = 0;

int j = 0;

for(int i = 1 ; i < len ; i++){

while(j && s[i] != s[j]) j = fail[j - 1];

if(s[i] == s[j]) j++;

fail[i] = j;

}

}

int KMP(char *P, char *T, int len1, int len2)

{

failure(P, len1);

int u, v;

u = v = 0;

int ans = 0;

while(v + len1 - u <= len2){

while(u && P[u] != T[v]) u = fail[u - 1];

if(P[u] == T[v]) u++;

if(u == len1){

u = fail[u - 1];

ans = v;

}

v++;

}

return ans;

}

int main()

{

// freopen("1006.in", "r", stdin);

int t;

scanf("%d", &t);

while(t--){

int n;

scanf("%d", &n);

scanf("%s", str1);

// printf("str1 = %s\n", str1);

for(int i = 0 ; i < n ; i++)

str1[i] = (25 - str1[i] + 'a') + 'a';

int ans1 = Minpre(str1, n);

for(int i = 0 ; i < n ; i++)

str2[i] = str1[n - i - 1];

str2
= '\0';

int ans2 = Minpre(str2, n);

for(int i = 0 ; i < n ; i++)

P[i] = str2[(i + ans2) % n], T[i] = T[i + n] = str2[i];

P
= '\0', T[n * 2] = '\0';

int temp = KMP(P, T, n, n * 2 - 1);

// printf("str1 = %s, str2 = %s\n", str1, str2);

// printf("P = %s, T = %s\n", P, T);

// printf("temp = %d", temp);

temp -= n - 1;

// if(temp < n && temp > ans2) ans2 = temp;

ans2 = n - 1 - temp;

// printf("ans1 = %d, ans2 = %d\n", ans1, ans2);

int flag = 0;

for(int i = 0 ; i < n ; i++){

int t1 = (i + ans1) % n;

int t2 = ((ans2 - i) % n + n ) % n;

// printf("t1 = %d, t2 = %d, str1[t1] = %c, str2[t2] = %c\n", t1, t2, str1[t1], str1[t2]);

if(str1[t1] > str1[t2]){

flag = -1; break;

}

else if(str1[t1] < str1[t2]){

flag = 1; break;

}

}

ans1++, ans2++;

// printf("ans1 = %d, ans2 = %d\n", ans1, ans2);

if(flag == 1){

printf("%d 0\n", ans1);

}

else if(flag == -1){

printf("%d 1\n", ans2);

}

else{

if(ans1 <= ans2)

printf("%d 0\n", ans1);

else

printf("%d 1\n", ans2);

}

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: