题目:题目链接
题目大意:
JB讨厌解决字符串问题。因此,当他的朋友土豆给他一个字符串问题要解决时,他会立即把它给你,并继续玩Genshin Impact,世界上最伟大的游戏。
给定一个字符串,然后对于每个非空前缀,您需要按照字典顺序找到最大的子串,并指出最大子串的最左边位置。
例如对于样例1的第二个位置'o',依题目要求有两个字串“po"和"o",字典序更大的是"po",则该子串的范围为[1,2]因此输出其左右边界1,2.
分析:
根据题意,我们要找的便是字串s,满足所有s的后缀的字典序都小于s。那么我们可以想到Lyndon分解,使用Duval算法在O(n)内可以求解。
Duval算法模板:(摘自OI Wiki)
// duval_algorithm
vector<string> duval(string const& s) {
int n = s.size(), i = 0;
vector<string> factorization;
while (i < n) {
int j = i + 1, k = i;
while (j < n && s[k] <= s[j]) {
if (s[k] < s[j])
k = i;
else
k++;
j++;
}
while (i <= k) {
factorization.push_back(s.substr(i, j - k));
i += j - k;
}
}
return factorization;
}
由于Lyndon分解求的是s的字典序严格小于s的所有后缀的字典序,我们将其逆用即可(改变大小于号)。
代码:
#include<bits/stdc++.h>
using namespace std;
string s;
int ans[1000005]={0};//存答案
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
cin>>s;
int len=s.length();
int i=0;
while (i<len) {//Duval算法
if (!ans[i])ans[i]=i+1;
int j=i+1,k=i;
while (j<len&&s[k]>=s[j]) {
if (!ans[j])ans[j]=i+1;
if (s[j]<s[k]) {
k=i;
}
else k++;
j++;
}
while (i<=k)i+=j-k;
}
for (int i=0;i<len;i++)cout<<ans[i]<<' '<<i+1<<endl;
}