标签:
题意:给一个字符串,求它的最小子串,使得原串是通过它重复得到的字符串的一个子串。
思路:先求最小长度,最小循环长度可以利用kmp的next数组快速得到,求出长度后然后利用字符串最小表示法求循环节的最小表示即可。
#pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define fillarray(a, b) memcpy(a, b, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; #ifndef ONLINE_JUDGE namespace Debug { void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} } #endif // ONLINE_JUDGE template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const double EPS = 1e-8; /* -------------------------------------------------------------------------------- */ const int maxn = 2e5 + 7; struct KMP { int next[maxn]; void GetNext(char s[]) { fillchar(next, 0); next[0] = next[1] = 0; for(int i = 1; s[i]; i++) { int j = next[i]; while(j && s[i] != s[j]) j = next[j]; next[i + 1] = s[j] == s[i]? j + 1 : 0; } } }; KMP kmp; char s[maxn]; void work(char s[], int n) { int i = 0, j = 1; /** 用i存最小表示的最小可能位置, 同时令j>i,因为0~i-1都不是最小表示*/ while (i < n && j < n) { while (s[i] == ‘0‘) i ++; umax(j, i + 1); while (s[j] == ‘0‘) j ++; //Debug::print(i, j, n); if (j >= n) break; int k = 0; while (s[i + k] == s[j + k] && k <= n) k ++; if (s[i + k] > s[j + k]) if (s[j + k] != ‘0‘) i += k + 1; else i += k; else if (s[i + k] != ‘0‘) j += k + 1; else j += k; //Debug::print(i, j, n); } int x = i < n? i : j; /** 最后一次可能跳跃导致i大于等于n,那么此时的j一定是最小表示 */ for (int i = x; i < x + n; i ++) { putchar(s[i]); } putchar(‘\n‘); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); // //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T; cin >> T; while (T --) { scanf("%s", s); int n = strlen(s); bool ok = false; for (int i = 0; s[i]; i ++) { if (s[i] != ‘0‘) { ok = true; break; } } if (!ok) { s[n ++] = ‘1‘; s[n] = 0; } kmp.GetNext(s); int len = n - kmp.next[n]; for (int i = len; i < 2 * len; i ++) s[i] = s[i - len]; s[2 * len] = 0; work(s, len); } return 0; }
[coj 1353 Guessing the Number]kmp,字符串最小表示法
标签:
原文地址:http://www.cnblogs.com/jklongint/p/4762074.html