标签:
题目链接:HDU 5769
题面:
2 a abc b bbb
Case #1: 3 Case #2: 3HintIn first case, all distinct substrings containing at least one a: a, ab, abc. In second case, all distinct substrings containing at least one b: b, bb, bbb.
题意:
给定一个字符串,问该字符串中包含某一字符的不重复子串的数量。
解题:
后缀数组的大致原理是懂的,自己写是写不出来的,勉强算是会用吧。这题可以先看一下,如何求某字符串的不重复子串的数量。
ans=sigma(length-sa[i]-height[i]),如何理解呢,sa[i]表示的是字典序排名为i的后缀,它的起始位置,length-sa[i],即为排名i的后缀的长度,height[i],是排名为i的串和它之前那个串的公共前缀长度,故length-sa[i]-height[i],(减去和字典序前一个的公共前缀)即为不重复子串数量。
而针对这题,需要包含特殊字符,故预先找到各个后缀中,离该后缀左侧最近的特殊字符的位置,综合该后缀不重复子串长度,取得最值。
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#define rep(i,n) for(int i = 0;i < n; i++)
#define sz 100005
#define LL long long
using namespace std;
char ori[sz];
int rk[sz],sa[sz],height[sz],w[sz],wa[sz],res[sz],pos[sz];
int min(int a,int b)
{
return a<b?a:b;
}
int max(int a,int b)
{
return a>b?a:b;
}
void getSa (int len,int up)
{
int *k = rk,*id = height,*r = res, *cnt = wa;
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[k[i] = w[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--)
sa[--cnt[k[i]]] = i;
int d = 1,p = 0;
while(p < len)
{
for(int i = len - d; i < len; i++) id[p++] = i;
rep(i,len) if(sa[i] >= d) id[p++] = sa[i] - d;
rep(i,len) r[i] = k[id[i]];
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[r[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--)
sa[--cnt[r[i]]] = id[i];
swap(k,r);
p = 0;
k[sa[0]] = p++;
rep(i,len-1)
{
if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]] == r[sa[i+1]]&& r[sa[i]+d] == r[sa[i+1]+d])
k[sa[i+1]] = p - 1;
else k[sa[i+1]] = p++;
}
if(p >= len) return ;
d *= 2,up = p, p = 0;
}
}
void getHeight(int len)
{
rep(i,len) rk[sa[i]] = i;
height[0] = 0;
for(int i = 0,p = 0; i < len - 1; i++)
{
int j = sa[rk[i]-1];
while(i+p < len&& j+p < len&& w[i+p] == w[j+p]) p++;
height[rk[i]] = p;
p = max(0,p - 1);
}
}
int getSuffix(char s[])
{
int len = strlen(s),up = 0;
for(int i = 0; i < len; i++)
{
w[i] = s[i];
up = max(up,w[i]);
}
w[len++] = 0;
getSa(len,up+1);
getHeight(len);
return len;
}
int main()
{
int t,l;
char c;
LL ans;
scanf("%d",&t);
for(int ix=1;ix<=t;ix++)
{
ans=0;
scanf(" %c",&c);
scanf("%s",ori);
getSuffix(ori);
l=strlen(ori);
int j;
for(pos[l]=l,j=l-1;j>=0;j--)
if(ori[j]==c)
pos[j]=j;
else
pos[j]=pos[j+1];
for(int i=1;i<=l;i++)
ans=ans+min(l-sa[i]-height[i],l-pos[sa[i]]);
printf("Case #%d: %lld\n",ix,ans);
}
return 0;
}标签:
原文地址:http://blog.csdn.net/david_jett/article/details/52072824