【BZOJ】【3790】神奇项链

Manacher算法/DP


  找出所有的回文串,看做是一个个线段,那么问题就转化成了用最少的线段将整个区间覆盖起来,可以重叠,那么这就是一个DP了= =

  Orz ZKY大爷,让蒟蒻开眼界了……头一次知道原来树状数组还可以反过来用0.0

 1 /**************************************************************
 2     Problem: 3790
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:176 ms
 7     Memory:3716 kb
 8 ****************************************************************/
 9  
10 //BZOJ 3790
11 #include<vector>
12 #include<cstdio>
13 #include<cstring>
14 #include<cstdlib>
15 #include<iostream>
16 #include<algorithm>
17 #define rep(i,n) for(int i=0;i<n;++i)
18 #define F(i,j,n) for(int i=j;i<=n;++i)
19 #define D(i,j,n) for(int i=j;i>=n;--i)
20 #define pb push_back
21 #define mk make_pair
22 #define fi first
23 #define se second
24 using namespace std;
25 typedef long long LL;
26 typedef pair<int,int> pii;
27 inline int getint(){
28     int r=1,v=0; char ch=getchar();
29     for(;!isdigit(ch);ch=getchar()) if(ch=='-')r=-1;
30     for(; isdigit(ch);ch=getchar()) v=v*10+ch-'0';
31     return r*v;
32 }
33 const int N=1e5+10,INF=~0u>>2;
34 /*******************template********************/
35 char s[N];
36 int a[N],p[N],f[N],d[N],n,m,size=0;
37 pii seg[N];
38 void get_seg(int l,int r){
39     if(l>r)return;
40     seg[++size]=mk(l,r);
41 }
42 bool cmp(pii a,pii b){
43     return a.se==b.se ? a.fi<b.fi : a.se<b.se;
44 }
45 void update(int x,int v){
46     for(;x;x-=x&-x) d[x]=min(d[x],v);
47 }
48 int query(int x){
49     int r=d[x];
50     for(;x && x<=size;x+=x&-x) r=min(d[x],r);
51     return r;
52 }
53 int main(){
54     while(scanf("%s",s)!=EOF){
55         memset(d,0x7f,sizeof d); d[0]=0;
56         memset(a,0,sizeof a);
57         memset(f,0,sizeof f);
58         m=n=strlen(s);
59         F(i,1,n) a[i<<1]=s[i-1];
60         n=n<<1|1; size=0;
61         int id=0,mx=0;
62         F(i,1,n){
63             if(mx>i) p[i]=min(p[2*id-i],mx-i);
64             else p[i]=0;
65             while(i-p[i]-1>0 && i+p[i]+1<=n && a[i-p[i]-1]==a[i+p[i]+1])p[i]++;
66             get_seg((i-p[i]+1)/2,(i+p[i]-1)/2);
67             if (p[i]+i>mx) mx=p[i]+i,id=i;
68         }
69         sort(seg+1,seg+size+1,cmp);
70         int ans=INF;
71         F(i,1,size){
72             f[i]=query(seg[i].fi-1)+1;
73             if (seg[i].se==m) ans=min(ans,f[i]);
74             update(seg[i].se,f[i]);
75         }
76         printf("%d\n",ans-1);
77     }
78     return 0;
79 }
View Code

3790: 神奇项链

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 126  Solved: 63
[Submit][Status][Discuss]

Description

母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和 一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。 

Input

输入数据有多行,每行一个字符串,表示目标项链的样式。 

Output

多行,每行一个答案表示最少需要使用第二个机器的次数。 

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行 

每行的字符串长度小于等于 50000 

Source

[Submit][Status][Discuss]
posted @ 2015-04-07 16:30  Tunix  阅读(196)  评论(0编辑  收藏  举报