给出一个字符串S[1..n],和一个整数k,现在需要求出在S中,对于所有长度为k的子串(k<n),可能不重叠出现的最大次数,如字符串:
aacaacbbcbbcbbc
k = 3
k = 3
其中aac不重叠出现次数为2,bbc不重叠出现的次数为3,则答案是3。
如果没有重复出现两次及两次以上的不重叠子串,输出0。
Input
第一行:一个整数k
第二行:一个字符串S,仅包含小写字母,字符串的长度不超过100000
Output
一个整数表示答案。
Sample Input
2
abcabdab
Sample Output
3
Source
xiaoze && zfy0701 @ XMU & CSU stringology invitation
按长度k对height分组,然后贪心同一个分组里面的子串,求同一个分组中最多有几个长度为k的子串是不重叠的,最后求出的最大不重叠数为解。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <climits>
#define MAX 100010
using namespace std;
struct node
{
int st,ed;
};
bool cmp(node a,node b)
{
if (a.ed == b.ed)
{
return a.st < b.st;
}
return a.ed < b.ed;
}
int mem[4][MAX];
int *sa;
int *rank;
int *nsa;
int *nrank;
int height[MAX];
int cnt[MAX];
int n,k;
char s[MAX];
node edges[MAX*2];
void make_sa()
{
sa = mem[0];
rank = mem[1];
nsa = mem[2];
nrank = mem[3];
memset(cnt,0,sizeof(cnt));
for (int i=0;i<n;i++)
{
++cnt[(int)s[i]];
}
for (int i=1;i<256;i++)
{
cnt[i]+=cnt[i-1];
}
for (int i=n-1;i>=0;i--)
{
sa[--cnt[(int)s[i]]] = i;
}
rank[sa[0]] = 0;
for (int i=1;i<n;i++)
{
rank[sa[i]] = rank[sa[i-1]];
if (s[sa[i]]!=s[sa[i-1]])
{
++rank[sa[i]];
}
}
for (int k=1;k<n&&rank[sa[n-1]]<n-1;k*=2)
{
for (int i=0;i<n;i++)
{
cnt[rank[sa[i]]] = i+1;
}
for (int i=n-1;i>=0;i--)
{
if (sa[i]-k>=0)
{
nsa[--cnt[rank[sa[i]-k]]] = sa[i] - k;
}
}
for (int i=n-k;i<n;i++)
{
nsa[--cnt[rank[i]]] = i;
}
nrank[nsa[0]] = 0;
for (int i=1;i<n;i++)
{
nrank[nsa[i]] = nrank[nsa[i-1]];
if (rank[nsa[i]]!=rank[nsa[i-1]]||rank[nsa[i]+k]!=rank[nsa[i-1]+k])
{
++nrank[nsa[i]];
}
}
swap(rank,nrank);
swap(sa,nsa);
}
}
void get_lcp_rmq()
{
int i,j,k;
for (i=0,k=0;i<n;i++)
{
if (rank[i]==0)
{
height[0] = k = 0;
}
else
{
if (k>0)
{
k--;
}
j = sa[rank[i]-1];
for (;s[i+k]==s[j+k];k++);
height[rank[i]] = k;
}
}
}
int solve(int len)
{
int ans = 1;
int kcnt;
for (int i=1;i<n;i++)
{
bool flag = false;
kcnt = 0;
while (i<n&&height[i]>=len)
{
flag = true;
edges[kcnt].st = sa[i-1];
edges[kcnt++].ed = sa[i-1]+len-1;
edges[kcnt].st = sa[i];
edges[kcnt++].ed = sa[i]+len-1;
i++;
}
sort(edges,edges+kcnt,cmp);
int tans = 1;
int mark = edges[0].ed;
for (int j=1;j<kcnt;j++)
{
if (edges[j].st>mark)
{
tans++;
mark = edges[j].ed;
}
}
if(tans>ans)
{
ans = tans;
}
if (flag)
{
i--;
}
}
if (ans<2)
{
return 0;
}
return ans;
}
int main()
{
scanf("%d",&k);
scanf("%s",s);
n = strlen(s);
s[n++] = 0;
make_sa();
get_lcp_rmq();
printf("%d\n",solve(k));
return 0;
}
#include <cstring>
#include <cstdio>
#include <climits>
#define MAX 100010
using namespace std;
struct node
{
int st,ed;
};
bool cmp(node a,node b)
{
if (a.ed == b.ed)
{
return a.st < b.st;
}
return a.ed < b.ed;
}
int mem[4][MAX];
int *sa;
int *rank;
int *nsa;
int *nrank;
int height[MAX];
int cnt[MAX];
int n,k;
char s[MAX];
node edges[MAX*2];
void make_sa()
{
sa = mem[0];
rank = mem[1];
nsa = mem[2];
nrank = mem[3];
memset(cnt,0,sizeof(cnt));
for (int i=0;i<n;i++)
{
++cnt[(int)s[i]];
}
for (int i=1;i<256;i++)
{
cnt[i]+=cnt[i-1];
}
for (int i=n-1;i>=0;i--)
{
sa[--cnt[(int)s[i]]] = i;
}
rank[sa[0]] = 0;
for (int i=1;i<n;i++)
{
rank[sa[i]] = rank[sa[i-1]];
if (s[sa[i]]!=s[sa[i-1]])
{
++rank[sa[i]];
}
}
for (int k=1;k<n&&rank[sa[n-1]]<n-1;k*=2)
{
for (int i=0;i<n;i++)
{
cnt[rank[sa[i]]] = i+1;
}
for (int i=n-1;i>=0;i--)
{
if (sa[i]-k>=0)
{
nsa[--cnt[rank[sa[i]-k]]] = sa[i] - k;
}
}
for (int i=n-k;i<n;i++)
{
nsa[--cnt[rank[i]]] = i;
}
nrank[nsa[0]] = 0;
for (int i=1;i<n;i++)
{
nrank[nsa[i]] = nrank[nsa[i-1]];
if (rank[nsa[i]]!=rank[nsa[i-1]]||rank[nsa[i]+k]!=rank[nsa[i-1]+k])
{
++nrank[nsa[i]];
}
}
swap(rank,nrank);
swap(sa,nsa);
}
}
void get_lcp_rmq()
{
int i,j,k;
for (i=0,k=0;i<n;i++)
{
if (rank[i]==0)
{
height[0] = k = 0;
}
else
{
if (k>0)
{
k--;
}
j = sa[rank[i]-1];
for (;s[i+k]==s[j+k];k++);
height[rank[i]] = k;
}
}
}
int solve(int len)
{
int ans = 1;
int kcnt;
for (int i=1;i<n;i++)
{
bool flag = false;
kcnt = 0;
while (i<n&&height[i]>=len)
{
flag = true;
edges[kcnt].st = sa[i-1];
edges[kcnt++].ed = sa[i-1]+len-1;
edges[kcnt].st = sa[i];
edges[kcnt++].ed = sa[i]+len-1;
i++;
}
sort(edges,edges+kcnt,cmp);
int tans = 1;
int mark = edges[0].ed;
for (int j=1;j<kcnt;j++)
{
if (edges[j].st>mark)
{
tans++;
mark = edges[j].ed;
}
}
if(tans>ans)
{
ans = tans;
}
if (flag)
{
i--;
}
}
if (ans<2)
{
return 0;
}
return ans;
}
int main()
{
scanf("%d",&k);
scanf("%s",s);
n = strlen(s);
s[n++] = 0;
make_sa();
get_lcp_rmq();
printf("%d\n",solve(k));
return 0;
}