算法题-第K个小子串
Posted 博客是个啥?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法题-第K个小子串相关的知识,希望对你有一定的参考价值。
第K小子串
输入一个字符串 s,s 由小写英文字母组成,保证 s 长度小于等于 5000 并且大于等于 1。在 s 的所有不同的子串中,输出字典序第 k 小的字符串。
字符串中任意个连续的字符组成的子序列称为该字符串的子串。
字母序表示英文单词在字典中的先后顺序,即先比较第一个字母,若第一个字母相同,则比较第二个字母的字典序,依次类推,则可比较出该字符串的字典序大小。
输入:
第一行输出一个字符串 s,保证 s 长度小于等于 5000 大于等于 1。
第二行一个整数 k (1<= k <= 5),保证 s 不同子串个数大于等于 k。
输出:
输出一个字符串表示答案。
这道题数据量不大,直接暴力枚举,利用set本身的有序性
#include <iostream>
#include <set>
using namespace std;
int main()
string str;
cin >> str;
int k;
cin >> k;
set<string> s;
for (int i = 0; i < str.size(); i++)
for (int j = i; j < str.size(); j++)
if (j - i + 1 > k)
break;
string t = str.substr(i, j - i + 1);
// cout << t << endl;
s.insert(t);
if (s.size() > k)
s.erase(--s.end());
cout << *(--s.end()) << endl;
[TJOI2015]弦论 题解(第k小子串)
题意:
对于一个给定的长度为n的字符串,求出它的第k小子串。
有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。
题解:
首先,因为t的原因,后缀数组较难实现,这里不讨论。
使用后缀自动机:
因为,这里需要按字典序考虑子串,所以要使用trs指针。
首先,计算出每个子串的贡献:t=0则为1,t=1则为出现次数。
然后,通过记搜算出匹配到每个点之后可以形成多少贡献。因为使用trs,无需考虑压缩。
最后,在每个节点处找到唯一一个应当向下计算的点,循环直到找到解。
代码:
#include <stdio.h>
#define ll long long
int trs[1000010][26],fa[1000010],len[1000010],sl=1,la=1;
int su[1000010];ll dp[1000010];
void insert(int c)
int np=++sl,p=la;
len[np]=len[la]+1;la=np;
while(p!=0&&trs[p][c]==0)
trs[p][c]=np;
p=fa[p];
if(p==0)
fa[np]=1;
else
int q=trs[p][c];
if(len[q]==len[p]+1)
fa[np]=q;
else
int nq=++sl;
len[nq]=len[p]+1;
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(int i=0;i<26;i++)
trs[nq][i]=trs[q][i];
while(p!=0&&trs[p][c]==q)
trs[p][c]=nq;
p=fa[p];
su[la]=1;
int fr[1000010],ne[1000010],v[1000010],bs=0;
void addb(int a,int b)
v[bs]=b;
ne[bs]=fr[a];
fr[a]=bs++;
void build()
for(int i=1;i<=sl;i++)
fr[i]=-1;
for(int i=2;i<=sl;i++)
addb(fa[i],i);
void dfs0(int u)
for(int i=fr[u];i!=-1;i=ne[i])
dfs0(v[i]);
su[u]|=su[v[i]];
void dfs1(int u)
for(int i=fr[u];i!=-1;i=ne[i])
dfs1(v[i]);
su[u]+=su[v[i]];
void dfs2(int u)
if(dp[u])
return;
dp[u]=su[u];
for(int i=0;i<26;i++)
if(trs[u][i])
dfs2(trs[u][i]);
dp[u]+=dp[trs[u][i]];
char zf[500010];
int main()
int t,k,u=1;
scanf("%s%d%d",zf,&t,&k);
for(int i=0;zf[i]!=0;i++)
insert(zf[i]-'a');
build();
if(t==0)dfs0(1);
else dfs1(1);
dfs2(1);
if(dp[1]-su[1]<k)
printf("-1");
return 0;
while(1)
if(u!=1)
if(su[u]>=k)
break;
k-=su[u];
int i;
for(i=0;i<26;i++)
if(trs[u][i]==0)
continue;
if(dp[trs[u][i]]>=k)
break;
k-=dp[trs[u][i]];
printf("%c",i+'a');
u=trs[u][i];
return 0;
以上是关于算法题-第K个小子串的主要内容,如果未能解决你的问题,请参考以下文章