思路:求最小/最大表示+kmp匹配
分析:
1 题目要求给定一个字符串求出最小和最大表示的rank和出现的times。
2 如果直接暴力枚举n 最大10^6肯定TLE,所以这了应该要用到的是求解一个字符串的最小和最大表示,然后利用kmp去匹配查找出现的次数
3 在利用kmp匹配的时候应该要注意不能多算,比如有abcder,那么用abcder去匹配abcderabcder的时候就有两次的匹配结果,但实际上这里只有一个,所以这个地方要注意。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define MAXN 2000010 int len; int next[MAXN/2]; char String[MAXN]; char minString[MAXN/2] , maxString[MAXN/2]; int minTimes , maxTimes; int minRank , maxRank; /*求最小表示的起始坐标*/ int getMin(){ int i = 0 , j = 1 , k = 0; while(i+k < len && j+k < len){ if(String[i+k] == String[j+k]) k++; else{ if(String[i+k] > String[j+k]) i = i+k+1; else j = j+k+1; k = 0; if(i == j)/*若滑动后i == j那么j++*/ j++; } } return min(i , j); } /*求最大表示的起始坐标*/ int getMax(){ int i = 0 , j = 1 , k = 0; while(i+k < len && j+k < len){ if(String[i+k] == String[j+k]) k++; else{ if(String[i+k] < String[j+k]) i = i+k+1; else j = j+k+1; k = 0; if(i == j)/*若滑动后i == j那么j++*/ j++; } } return min(i , j); } /*求出最小表示*/ void getMinString(){ int pos = 0; for(int i = minRank ; i < minRank+len/2 ; i++) minString[pos++] = String[i]; minString[pos] = '\0'; } /*求出最大表示*/ void getMaxString(){ int pos = 0; for(int i = maxRank ; i < maxRank+len/2 ; i++) maxString[pos++] = String[i]; maxString[pos] = '\0'; } /*求next数组*/ void getNext(char *pattern){ int m = strlen(pattern); next[0] = next[1] = 0; for(int i = 1 ; i < m ; i++){ int j = next[i]; while(j && pattern[i] != pattern[j]) j = next[j]; next[i+1] = pattern[i] == pattern[j] ? j+1 : 0; } } /*kmp匹配找到有几个*/ int find(char *pattern){ int count = 0; int m = strlen(pattern); int j = 0; for(int i = 0 ; i < len-1 ; i++){/*这里只要判断到len-1即可,这样就可以避免多算了一次*/ while(j && pattern[j] != String[i]) j = next[j]; if(pattern[j] == String[i]) j++; if(j == m) count++; } return count; } int main(){ while(scanf("%s" , String) != EOF){ int flag; char tmp[MAXN]; memcpy(tmp , String , sizeof(String)); strcat(String , tmp); len = strlen(String); /*求字符串的最小表示*/ minRank = getMin(); getMinString(); getNext(minString); minTimes = find(minString); /*求字符串的最大表示*/ maxRank = getMax(); getMaxString(); getNext(maxString); maxTimes = find(maxString); /*输出*/ printf("%d %d %d %d\n" , minRank+1 , minTimes , maxRank+1 , maxTimes); } return 0; }
时间: 2024-10-21 17:45:23