string string string
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1672 Accepted Submission(s): 482
Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.
For each test case, there are two lines:
the first line contains an integer k (k≥1) which is described above;
the second line contain a string s (length(s)≤105).
It's guaranteed that ∑length(s)≤2∗106.
liuyiding | We have carefully selected several similar problems for you: 6216 6215 6214 6213 6212
解題思路:後綴數組,先處理出height數組,然後每次取連續的k個前綴,求他們的lcp,就是在這段區間出現k次的字符串的數量,但是這些字符串並不是每個字符串都出現k次,可能會出現大於k次的情況,我們減去這部分就行,在這段區間的上邊界和下邊界各處理一下就行,我們可以用st表或者線段樹維護一下區間lcp最小值就行。注意:每次tp數組或者rrank數組要清0,不然會影響到height的計算。。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
typedef long long LL;
int kk;
int dp[maxn][30];
int Log[maxn];
char s[maxn];
int n, m;
int a[maxn];//原數組
int rrank[maxn];//第一關鍵字
int Rank[maxn];//第i個前綴排第幾
int tp[maxn];//第二關鍵字,序號爲第二關鍵字的排名,值爲對應的第一關鍵字的位置
int c[maxn];//用於基數排序用的數組
int Sa[maxn];//後綴數組,排名爲i的後綴是哪一個後綴
int Height[maxn];//排名爲i的後綴與排名爲i - 1的後綴的lcp
bool judge(int *x, int loc, int ww)
{
if(x[Sa[loc]] == x[Sa[loc - 1]] && x[Sa[loc] + ww] == x[Sa[loc - 1] + ww]) return true;
else return false;
}
void suffix()
{
memset(tp, -1, sizeof(tp));//注意,一定要清0
for(int i = 1; i <= n; i++) rrank[i] = a[i];
for(int i = 1; i <= n; i++) tp[i] = i;
for(int i = 0; i <= 128; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
for(int i = 1; i <= 128; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
m = 128;
for(int w = 1, p = 0; w <= n; w += w, m = p)
{
p = 0;
for(int i = n - w + 1; i <= n; i++) tp[++p] = i;
for(int i = 1; i <= n; i++)
{
if(Sa[i] > w) tp[++p] = Sa[i] - w;
}
for(int i = 0; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
for(int i = 1; i <= m; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
for(int i = 0; i <= n; i++) tp[i] = rrank[i];//重新計算rank的值
rrank[Sa[1]] = 1;
p = 1;
for(int i = 2; i <= n; i++)
{
if(judge(tp, i, w)) rrank[Sa[i]] = p;
else rrank[Sa[i]] = ++p;
}
if(p >= n) break;
}
for(int i = 1; i <= n; i++)
{
Rank[Sa[i]] = i;
}
int k = 0;
Height[1] = 0;
for(int i = 1; i <= n; i++)
{
if(k) k--;
while(a[i + k] == a[Sa[Rank[i] - 1] + k])
{
k++;
}
Height[Rank[i]] = k;
}
}
void initRmq()
{
Log[0] = -1;
for(int i = 1; i <= n; i++)
{
if((i&(i - 1)) == 0) Log[i] = Log[i - 1] + 1;
else Log[i] = Log[i - 1];
dp[i][0] = Height[i];
}
for(int j = 1; j <= 25; j++)
{
for(int i = 1; i <= n && (i + (1<<j) - 1) <= n; i++)
{
dp[i][j] = min(dp[i][j - 1], dp[i + (1<<(j - 1))][j - 1]);
}
}
}
int rmq(int l, int r)
{
int d = r - l + 1;
d = Log[d];
return min(dp[l][d], dp[r - (1<<d) + 1][d]);
}
void init()
{
n = strlen(s);
memset(Height, 0, sizeof(Height));
memset(a, -1, sizeof(a));//注意,一定要重置。在這裏wa了無數次
for(int i = 0; i < n; i++)
{
a[i + 1] = s[i];
}
}
int main()
{
//freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;
//freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &kk);
scanf("%s", s);
init();
suffix();
initRmq();
LL ans = 0;
if(kk == 1)
{
for(int i = 1; i <= n; i++)
{
LL value = (LL)(n - Sa[i] + 1);
LL value1, value2;
value1 = (LL)Height[i];
if(i + 1 <= n) value2 = (LL)Height[i + 1];
else value2 = 0;
LL Max = max(value1, value2);
if(value > Max) ans += value - Max;
}
}
else
{
for(int i = 1; i + 1 <= n && i + (kk - 1) <= n; i++)
{
LL value = (LL)rmq(i + 1, i + (kk - 1));
LL value1 = (LL)rmq(i, i + (kk - 1));
LL value2;
if(i + kk <= n) value2 = (LL)rmq(i + 1, i + kk);
else value2 = 0;
LL Max = max(value1, value2);
if(value > Max) ans += value - Max;
}
}
printf("%I64d\n", ans);
}
return 0;
}