http://acm.hdu.edu.cn/showproblem.php?pid=4691
http://blog.csdn.net/fire_cat11211022/article/details/9908545 详细的后缀数组有关问题的解答
解析:当然用后缀数组最方便,在后缀数组中有很多重要的定义和性质,现在我们来认识一些:
定义:LCP(i,j)=suffix(SA[i])与suffix[SA[j]]的最长公共前缀长度,即排号序后的后缀中第i名和第j名的最长公共前缀长度。
然后我们再用一个重要的性质就可以求出LCP(i,j)了,性质描述:LCP(i,j)=min{LCP(k-1,k)} i
而对于LCP(k-1,k)我们有height数组啊,比如我们要求suffix(i)和suffix(j)的最长公共前缀,就相当于求height[rank[i]]到height[rank[j]]之间的最小值。
至于区间求最小值,线段树是个很好的选择,到此问题圆满解决。
#include //sort
#include //memset
#include
#include
#define MAX 2000100
using namespace std;
const int MAX_SFX = 210000;
struct Sfx
{
int i;
int key[2];
bool operator < (const Sfx& s) const
{
return key[0] < s.key[0]
|| key[0] == s.key[0] && key[1] < s.key[1];
}
};
typedef struct
{
int l;
int r;
int minn;
} Tree;
Tree tree[MAX*4];
int build(int i,int l,int r) //建树
{
int mid;
tree[i].l=l;
tree[i].r=r;
tree[i].minn=MAX;
if(l==r)
{
return 0;
}
mid=(l+r)/2;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
}
int insert(int i,int k,int v) //插入
{
tree[i].minn=v < tree[i].minn? v:tree[i].minn;
if(tree[i].l==tree[i].r)
return 0;
else
{
int mid=(tree[i].l+tree[i].r)/2;
if(mid=tree[i].r))
{
return tree[i].minn;
}
ans=MAX;
mid=(tree[i].l+tree[i].r)/2;
if (x<=mid) ans=min(ans,findmin(i*2,x,y));
if (y>mid) ans=min(ans,findmin(i*2+1,x,y));
return ans;
}
int g_buf[MAX_SFX + 1];
Sfx g_tempSfx[2][MAX_SFX], *g_sa = g_tempSfx[0];
void cSort(Sfx* in, int n, int key, Sfx* out)
{
int* cnt = g_buf;
memset( cnt, 0, sizeof(int) * (n + 1) );
for (int i = 0; i < n; i++)
{
cnt[ in[i].key[key] ]++;
}
for (int i = 1; i <= n; i++)
{
cnt[i] += cnt[i - 1];
}
for (int i = n - 1; i >= 0; i--)
{
out[ --cnt[ in[i].key[key] ] ] = in[i];
}
}
void buildSA(char* text, int len)
{
Sfx *temp = g_tempSfx[1];
int* rank = g_buf;
for (int i = 0; i < len; i++)
{
g_sa[i].i = g_sa[i].key[1] = i;
g_sa[i].key[0] = text[i];
}
sort(g_sa, g_sa + len);
for (int i = 0; i < len; i++)
{
g_sa[i].key[1] = 0;
}
int wid = 1;
while (wid < len)
{
rank[ g_sa[0].i ] = 1;
for (int i = 1; i < len; i++)
{
rank[ g_sa[i].i ] = rank[ g_sa[i - 1].i ];
if ( g_sa[i-1] < g_sa[i] )
{
rank[ g_sa[i].i ]++;
}
}
for (int i = 0; i < len; i++)
{
g_sa[i].i = i;
g_sa[i].key[0] = rank[i];
g_sa[i].key[1] = i + wid < len? rank[i + wid]: 0;
}
cSort(g_sa, len, 1, temp);
cSort(temp, len, 0, g_sa);
wid *= 2;
}
}
int getLCP(char* a, char* b)
{
int l=0;
while(*a && *b && *a==*b)
{
l++;
a++;
b++;
}
return l;
}
void getLCP(char* text, Sfx* sfx, int len, int* lcp)
{
int* rank = g_buf;
for (int i=0, r=0; i < len; i++, r++)
{
rank[ sfx[i].i ] = r;
}
lcp[0] = 0;
if (rank[0])
{
lcp[ rank[0] ] = getLCP( text, text + sfx[ rank[0]-1 ].i );
}
for (int i = 1; i < len; i++)
{
if ( !rank[i] )
{
continue;
}
if (lcp[ rank[i - 1] ] <= 1)
{
lcp[ rank[i] ] = getLCP( text+i, text+sfx[ rank[i]-1 ].i );
}
else
{
int L = lcp[ rank[i - 1] ] - 1;
lcp[rank[i]] = L+getLCP(text+i+L, text+sfx[rank[i]-1].i+L);
}
}
}
int rank[100010];
char str[100010];
int main()
{
while(~scanf("%s",str))
{
int lcp[100010];
int len=strlen(str);
buildSA(str,len); //获取sa数组
getLCP(str,g_sa,len, lcp); //获取height[]即lcp[] g_buf即 rank[];
build(1,0,len-1);
for(int i=0; ig_buf[lx]) //比较rank的大小 决定起始位置
sum=findmin(1,g_buf[lx]+1,g_buf[x]);
else
sum=findmin(1,g_buf[x]+1,g_buf[lx]);
sum=min(sum,min(y-x,ly-lx));//三个长度的最小
}
ans2-=sum;
if(sum==0) //注意等于0时也是1位
sum1++;
else
{
while(sum)
{
sum/=10;
sum1++;
}
}
ans2=ans2+sum1+y-x+2;
ly=y; lx=x;
}
printf("%I64d %I64d\n",ans1,ans2);
}
return 0;
}