【bzoj3790】 神奇项链 mancher+树状数组优化dp

来源:互联网 发布:js金沙.com 11 编辑:程序博客网 时间:2024/06/06 04:20

这道题首先用manacher求出回文子串长度,之后问题就转化为已知一堆线段,要用最少的线段,覆盖整个区间,很明显可以用dp来做,f[i]表示1到i这个区间最少用多少线段覆盖,f[i]=min{f[j]} (r[j]<=l[j]-1)。按理说这个方程可以用线段树优化,被黄学长的树状数组维护最小值吓尿了。

http://hzwer.com/5488.html


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 100010#define inf 1000000000using namespace std;struct yts{int l,r;}q[maxn*2];int n,num,m;char s[maxn],a[2*maxn];int p[2*maxn],c[maxn];void add(int x,int y){x=x/2+1;y=y/2-1;if (x>y) return;q[++num].l=x;q[num].r=y;}void manacher(){m=2*n+1;for (int i=1;i<=n;i++){a[i*2]=s[i];a[i*2+1]='#';}a[0]='+';a[1]='#';a[m+1]='-';int mx=0,id=0;for (int i=1;i<=m;i++){if (mx>i) p[i]=min(p[2*id-i],mx-i);else p[i]=1;while (a[i-p[i]]==a[i+p[i]]) p[i]++;add(i-p[i],i+p[i]);if (i+p[i]>mx){mx=i+p[i];id=i;}}}bool cmp(yts x,yts y){return x.r<y.r;}int query(int i){if (!i) return 0;int x=inf;while (i<=n){x=min(x,c[i]);i+=i&-i;}return x;}void modify(int i,int x){while (i){c[i]=min(c[i],x);i-=i&-i;}}int main(){while (scanf("%s",s+1)!=EOF){num=0;int ans=inf;n=strlen(s+1);for (int i=1;i<=n;i++) c[i]=inf;manacher();sort(q+1,q+num+1,cmp);for (int i=1;i<=num;i++){int x=query(q[i].l-1)+1;modify(q[i].r,x);if (q[i].r==n) ans=min(ans,x);}printf("%d\n",ans-1);}return 0;}


0 0
原创粉丝点击