题目大意:给定一个串,问这个串最少可以由回文串拼接多少次而成(拼接可以重叠)
首先将每两个字符之间插入占位符,然后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) ); } }
原文地址:http://blog.csdn.net/popoqqq/article/details/41866751