4310: 跳蚤
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 306 Solved: 146
[ Submit][ Status][ Discuss]
Description
很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。
首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个。他称其为“魔力串”。
现在他想找一个最优的分法让“魔力串”字典序最小。
Input
第一行一个整数 k。
接下来一个长度不超过 105 的字符串 S。
Output
输出一行,表示字典序最小的“魔力串”。
Sample Input
13
bcbcbacbbbbbabbacbcbacbbababaabbbaabacacbbbccaccbcaabcacbacbcabaacbccbbcbcbacccbcccbbcaacabacaaaaaba
bcbcbacbbbbbabbacbcbacbbababaabbbaabacacbbbccaccbcaabcacbacbcabaacbccbbcbcbacccbcccbbcaacabacaaaaaba
Sample Output
cbc
HINT
S的长度<=100000
Source
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 1E5 + 10;
const int T = 19;
typedef long long LL;
int n,k,l,r,height[maxn],rank[maxn],sa[maxn],t1[maxn]
,t2[maxn],c[maxn],Ans[maxn][T],bin[maxn],len[maxn];
char s[maxn];
void Get_SA(int m)
{
int *x = t1,*y = t2;
for (int i = 1; i <= n; i++) ++c[x[i] = s[i]];
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i; i--) sa[c[x[i]]--] = i;
for (int k = 1; k < n; k <<= 1)
{
int p = 0;
for (int i = n; i > n - k; i--) y[++p] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++p] = sa[i] - k;
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) ++c[x[y[i]]];
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i; i--) sa[c[x[y[i]]]--] = y[i];
swap(x,y); p = 1; x[sa[1]] = 1;
for (int i = 2; i <= n; i++)
x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p : ++p;
if (p >= n) return; m = p;
}
}
void Get_Height_And_Rank()
{
int k = 0;
for (int i = 1; i <= n; i++) rank[sa[i]] = i;
for (int i = 1; i <= n; i++)
{
if (k) --k;
int j = sa[rank[i] - 1];
while (s[i+k] == s[j+k]) ++k;
height[rank[i]] = k;
}
}
void RMQ_Pre()
{
for (int i = 1; i <= n; i++)
{
bin[i] = (1<<bin[i-1]+1) < i ? bin[i-1]+1 : bin[i-1];
Ans[i][0] = height[i]; len[i] = (1<<bin[i]);
}
for (int j = 1; j < T; j++)
for (int i = 1; i <= n; i++)
{
int Nex = i + (1<<j-1); if (Nex > n) break;
Ans[i][j] = min(Ans[i][j-1],Ans[Nex][j-1]);
}
}
void Get(LL res)
{
LL tot = 0;
for (int i = 1; res; i++)
{
int now = n - sa[i] - height[i] + 1;
if (res > now) res -= 1LL*now;
else l = sa[i],r = sa[i] + height[i] + res - 1,res = 0;
}
}
int RMQ(int x,int y)
{
int k = y - x + 1;
return min(Ans[x][bin[k]],Ans[y-len[k]+1][bin[k]]);
}
int LCP(int x,int y)
{
if (x == y) return n - x + 1;
x = rank[x]; y = rank[y];
if (x > y) swap(x,y);
return RMQ(x + 1,y);
}
bool cmp(int l1,int r1,int l2,int r2)
{
int len1 = r1 - l1 + 1,len2 = r2 - l2 + 1,len = LCP(l1,l2);
if (len >= len2 && len1 > len2) return 1;
if (len >= len1 && len2 >= len1) return 0;
if (len >= len1 && len >= len2) return len1 > len2;
return s[l1 + len] > s[l2 + len];
}
bool Judge(LL now)
{
int sum = 0,last = n; Get(now);
for (int i = n; i; i--)
{
if (s[i] > s[l]) return 0;
if (cmp(i,last,l,r)) ++sum,last = i;
if (sum > k) return 0;
}
return sum + 1 <= k;
}
void Print(LL goal)
{
Get(goal);
for (int i = l; i <= r; i++) putchar(s[i] + 'a' - 1);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> k; scanf("%s",s + 1); n = strlen(s + 1);
for (int i = 1; i <= n; i++) s[i] = s[i] - 'a' + 1;
Get_SA(26); Get_Height_And_Rank(); RMQ_Pre();
LL L = 1,R = 0;
for (int i = 1; i <= n; i++) R += 1LL*(n - sa[i] + 1 - height[i]);
while (R - L > 1)
{
LL mid = (L + R) >> 1LL;
if (Judge(mid)) R = mid;
else L = mid;
}
Print(Judge(L) ? L : R);
return 0;
}