bzoj 3790(manachery+树状数组)

3790: 神奇项链

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 298   Solved: 146
[ Submit][ Status][ Discuss]

Description

母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。 

Input

输入数据有多行,每行一个字符串,表示目标项链的样式。 

Output

多行,每行一个答案表示最少需要使用第二个机器的次数。 

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行 

每行的字符串长度小于等于 50000 


解题思路:先用manachery求出f数组,然后就相当于线段覆盖问题,用树状数组优化dp来做。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,len;
char c[50100];
char s[110000];
int f[110000],sum[110000],ans[110000];


void manachery()
 {
    s[0]='$';
    for (int i=1;i<=2*len;++i)
     {
      if (i%2==1)
      {
      s[i]=c[(i+1)/2];
}else
 s[i]='#';
}
s[2*len+1]='&';
int u=0; int mx=0;
for (int i=1;i<=2*len;++i)
{
  int j=0;
  if (mx>i)
   {
    j=min(mx-i,f[2*u-i]);
}
  while (s[i+j]==s[i-j])++j;
  f[i]=j-1; if (i+f[i]>mx)mx=i+f[i],u=i;
}
 }
 
int query(int now)
 {
  int zhi=0x7fffffff;
  while (now<=2*len)
  {
  zhi=min(zhi,sum[now]);
  now+=now&-now;
 }
return zhi;
 }


void change(int zhi,int r)
 {
  while (r>0)
  {
  sum[r]=min(sum[r],zhi);
  r-=r&-r;
 }
 }


int main()
{
while (scanf("%s",c+1)!=EOF)
{
  len=strlen(c+1);
  manachery();
  memset(sum,0x7f,sizeof(sum)); memset(ans,0,sizeof(ans)); ans[1]=1; sum[1]=1;
  for (int i=2;i<=2*len-1;++i)
   {
    int l=i-f[i]; int r=i+f[i];
    ans[i]=query(i);
    int yu;
    if (l==1) yu=1;else yu=query(l-1)+1;
ans[i]=min(ans[i],yu);
change(yu,r);
}
 if (ans[2*len-1]>1000000) ans[2*len-1]=0;
 printf("%d\n",ans[2*len-1]-1);

}


你可能感兴趣的:(bzoj 3790(manachery+树状数组))