题目大意:给定一个串,问这个串最少可以由回文串拼接多少次而成(拼接可以重叠)
首先将每两个字符之间插入占位符,然后Hash+二分搞出所有极大回文串(可以用manacher,我不会)
问题转化成了给定一些区间,求最少的能覆盖整个数轴的区间
将所有区间按照某一端点排序 然后上树状数组即可
回头还是去学学manacher吧。。。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define BASE 131
using namespace std;
typedef unsigned long long ll;
struct Interval{
int x,y;
bool operator < (const Interval &Y) const
{
return x < Y.x ;
}
}intervals[M];
int n;
char s[M],_s[M<<1];
ll sum1[M<<1],sum2[M<<1],power[M<<1];
namespace BIT{
int c[M];
inline void Update(int x,int y)
{
for(;x;x-=x&-x)
c[x]=min(c[x],y);
}
inline int Get_Ans(int x)
{
int re=0x3f3f3f3f;
for(;x<=n;x+=x&-x)
re=min(re,c[x]);
return re;
}
}
void Initialize()
{
memset(_s,0,sizeof _s);
memset(sum1,0,sizeof sum1);
memset(sum2,0,sizeof sum2);
memset(BIT::c,0x3f,sizeof BIT::c);
}
bool Judge(int x,int len)
{
int l=x-len+1;
int r=x+len-1;
return sum1[r]-sum1[l-1]*power[r-l+1]==
sum2[l]-sum2[r+1]*power[r-l+1];
}
int Bisection(int x)
{
int l=1,r=min(x,n-x+1);
while(l+1<r)
{
int mid=l+r>>1;
if( Judge(x,mid) )
l=mid;
else
r=mid;
}
if( Judge(x,r) )
return r;
return l;
}
int main()
{
int i;
for(i=1,power[0]=1;i<M<<1;i++)
power[i]=power[i-1]*BASE;
while(~scanf("%s",s+1) )
{
Initialize();
n=strlen(s+1);
for(i=1;i<=n;i++)
{
_s[i<<1]=s[i];
_s[i+i-1]='#';
}
_s[n=n+n+1]='#';
for(i=1;i<=n;i++)
sum1[i]=sum1[i-1]*BASE+_s[i];
for(i=n;i;i--)
sum2[i]=sum2[i+1]*BASE+_s[i];
for(i=1;i<=n;i++)
{
int temp=Bisection(i);
intervals[i].x=i-temp+1;
intervals[i].y=i+temp-1;
}
sort(intervals+1,intervals+n+1);
BIT::Update(1,-1);
for(i=1;i<=n;i++)
{
int temp=BIT::Get_Ans(intervals[i].x);
BIT::Update(intervals[i].y,temp+1);
}
printf("%d\n", BIT::Get_Ans(n) );
}
}