3790: 神奇项链
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 298 Solved: 146
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
abacada
abcdef
Sample Output
2
5
HINT
每行的字符串长度小于等于 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);
}
}