bzoj 3790 神奇项链(Manacher,DP+BIT | 贪心)

【题意】

你可以产生一个回文串,也可以将两个串合并成一个串,问产生目标串需要的最少合并次数。

【思路】

Manacher求出每个位置可以向两边延伸的最长回文串。

则题目转化为有若干条线段,求最少的线段将[1..n]覆盖。贪心DP皆可上,DP需要BIT优化一下。

【代码】

 1 #include<set>
 2 #include<cmath>
 3 #include<queue>
 4 #include<vector>
 5 #include<cstdio>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
11 using namespace std;
12
13 typedef long long ll;
14 const int N = 2e5+10;
15 const int inf = 1e9;
16
17 struct Node
18 {
19     int l,r;
20     bool operator < (const Node& rhs) const
21     {
22         return r<rhs.r;
23     }
24 } q[N];
25 int tot;
26
27 char s[N],a[N];
28 int n,m,p[N];
29
30 int C[N];
31 void upd(int x,int v)
32 {
33     for(int i=x;i;i-=i&(-i))
34         C[i]=min(C[i],v);
35 }
36 int query(int x)
37 {
38     if(x==0) return 0;
39     int res=inf;
40     for(int i=x;i<=n;i+=i&(-i))
41         res=min(res,C[i]);
42     return res;
43 }
44
45 void Add(int l,int r)
46 {
47     l=l/2+1,r=r/2-1;
48     if(l>r) return ;
49     q[++tot]=(Node){l,r};
50 }
51 void Manacher()
52 {
53     m=2*n+1;
54     for(int i=1;i<=n;i++)
55     {
56         a[i<<1]=s[i];
57         a[i<<1|1]=‘#‘;
58     }
59     a[0]=‘+‘,a[m+1]=‘-‘,a[1]=‘#‘;
60     int mx=0,id;
61     for(int i=1;i<=m;i++)
62     {
63         if(mx>i) p[i]=min(mx-i,p[id*2-i]);
64         else p[i]=1;
65         while(a[i-p[i]]==a[i+p[i]]) p[i]++;
66         Add(i-p[i],i+p[i]);
67         if(p[i]+i>mx) mx=i+p[i],id=i;
68     }
69 }
70
71 int dp()
72 {
73     int ans=inf;
74     sort(q+1,q+tot+1);
75     FOR(i,1,tot)
76     {
77         int x=query(q[i].l-1)+1;
78         upd(q[i].r,x);
79         if(q[i].r==n) ans=min(ans,x);
80     }
81     return ans;
82 }
83
84 int main()
85 {
86     while(scanf("%s",s+1)==1)
87     {
88         memset(p,0,sizeof(p));
89         tot=0;
90         n=strlen(s+1);
91         FOR(i,1,n) C[i]=inf;
92         Manacher();
93         printf("%d\n",dp()-1);
94     }
95     return 0;
96 }
时间: 2024-08-26 22:27:42

bzoj 3790 神奇项链(Manacher,DP+BIT | 贪心)的相关文章

BZOJ 3790 神奇项链 hash/后缀自动机+贪心

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

BZOJ 3790 神奇项链(manacher+DP+树状数组)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3790 [题目大意] 问最少用几个回文串可以构成给出串,重叠部分可以合并 [题解] 我们先用manacher处理出每个位置最长的回文串, 那么题目就转化为求最少的线段来覆盖全区间,那就是经典的dp题了, dp[i]=min(dp[j]+1)(i线段的左端点-1和j线段的右端点有交) 用树状数组优化一下即可. [代码] #include <cstdio> #include <al

BZOJ 3790 神奇项链 Hash+二分+树状数组

题目大意:给定一个串,问这个串最少可以由回文串拼接多少次而成(拼接可以重叠) 首先将每两个字符之间插入占位符,然后Hash+二分搞出所有极大回文串(可以用manacher,我不会) 问题转化成了给定一些区间,求最少的能覆盖整个数轴的区间 将所有区间按照某一端点排序 然后上树状数组即可 回头还是去学学manacher吧... #include <cstdio> #include <cstring> #include <iostream> #include <algo

BZOJ 3790 神奇项链 Hash+二分

题目大意:给出一个字符串,求出这是最少由多少个回文串组成的.回文串可以重叠. 思路:将原串中的所有回文串都统计出来,然后变成一些区间,问题就转化成了区间并的问题. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 400010 #define BASE 1333 #define INF 0x3f3f3f3f using

【BZOJ-3790】神奇项链 Manacher + 树状数组(奇葩) + DP

3790: 神奇项链 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 304  Solved: 150[Submit][Status][Discuss] Description 母亲节就要到了,小 H 准备送给她一个特殊的项链.这个项链可以看作一个用小写字母组成的字符串,每个小写字母表示一种颜色.为了制作这个项链,小 H 购买了两个机器.第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个

【bzoj3790】神奇项链——manacher+贪心

听说这道题可以用树状数组什么鬼的做,反正我不会,还是老老实实打manacher+贪心大法吧-- 我们只要在跑manacher的过程中,用一个结构体(也可以直接用数组)来记录以每个字符为对称轴的最长回文的最左端和最右端,然后就得到了一些线段,于是问题完美地转换成了求取最少段的线段来完全覆盖一个区间了,直接排完序后贪心一遍即可.当然这里面有些比较是不必要的,但我也懒得去优化了. 具体实现细节看代码: #include<cstdio> #include<cstring> #include

【BZOJ】【3790】神奇项链

Manacher算法/DP 找出所有的回文串,看做是一个个线段,那么问题就转化成了用最少的线段将整个区间覆盖起来,可以重叠,那么这就是一个DP了= = Orz ZKY大爷,让蒟蒻开眼界了……头一次知道原来树状数组还可以反过来用0.0 1 /************************************************************** 2 Problem: 3790 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6

BZOJ 1006 神奇的国度(弦图的染色数)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1006 题意:给定一个弦图,求最小染色数.就是用最小数目的颜色进行染色使得任意两个相邻的节点颜色不同. 思路:(1)求出弦图的完美消除序列. (2)贪心染色.从后向前用可以用的编号最小的颜色染色.在这里因为最小染色等于最大团,我直接求的最大团.为什么最小染色等于最大团呢?最大团w(G) 是包含点数最多的团,最小染色x(G)是相邻点不同色的最小颜色个数.那么w(G)<=x(G),因为最大团

BZOJ 1076 奖励关(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1076 题意:n种宝物,每个宝物有两个属性: (1)价值:(2)该宝物的集合S,只有得到了集合S中的宝物时才能得到该宝物.每次从一个黑箱子中随机拿出一个宝物k,若k的集合S中的宝物都已经得 到,则k可要(也可不要),否则k不能要.每次拿到任意宝物概率相等.求随机拿K次的最大期望得分. 思路:从后向前,设f[i][j]表示到第i次拿完宝物,状态为j的最大价值.枚举i+1次拿的宝物k,若k的