bzoj3790 神奇项链
题目大意:
你有两种机器,一种可以生产回文串,一种可以链接两个串。链接时可以覆盖相同前/后缀。
给出多个串,求最少链接多少次。
题解:
先做manacher找出最长回文,然后贪心发现这是线段覆盖。
排序然后搞就行了。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s0[50050],s[100050]; int len,n,p[100050]; struct node { int l,r; }d[100050]; void manacher() { int mid = 0,mx = 0; for(int i=1;i<=n;i++) { if(i<=mx)p[i]=min(p[2*mid-i],mx-i+1); else p[i]=1; while(s[i+p[i]]==s[i-p[i]])p[i]++; d[i].l=i-p[i]+1,d[i].r=i+p[i]-1; if(i+p[i]-1>mx) { mid=i; mx=i+p[i]-1; } } } bool cmp(node a,node b) { if(a.l!=b.l)return a.l<b.l; return a.r<b.r; } int main() { while(scanf("%s",s0+1)>0) { len = strlen(s0+1); s[0]='!',n=0; for(int i=1;i<=len;i++) { s[++n]='#'; s[++n]=s0[i]; } s[++n]='#',s[n+1]='@'; manacher(); sort(d+1,d+n+1,cmp); int cnt = 0,now = 0,mxr=0; for(int i=1;i<=n&&now!=n;) { mxr=0; while(d[i].l<=now+1)mxr=max(mxr,d[i].r),i++; i--; cnt++; now=mxr; } printf("%d\n",cnt-1); } return 0; }