[BZOJ3790]神奇项链
[BZOJ3790]神奇项链
试题描述
母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。
输入
输入数据有多行,每行一个字符串,表示目标项链的样式。
输出
多行,每行一个答案表示最少需要使用第二个机器的次数。
输入示例
abcdcba
abacada
abcdef
输出示例
0 2 5
数据规模及约定
每个测试数据,输入不超过 5行
每行的字符串长度小于等于 50000
题解
可以 dp 一下,设 f[i] 表示前 i 个字符中,最少由几个回文串可重叠地拼接而成,那么每次转移我们可以找到位置 i 的 P[i],查询 [i - P[i] + 1, n] 这个区间中的最小值 minv,然后用 minv + 1 更新 f[i+P[i]-1]。用线段树可以很容易地优化。
当然求出 P[i] 数组后,每个位置 i 可以转化成 [i - P[i] + 1, i + P[i] - 1] 这样的区间,然后贪心就好了。
这里只放线段树 + dp 的版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; #define maxn 100010 #define oo 2147483647 int f[maxn], mnv[maxn<<2]; void build( int L, int R, int o) { if (L == R) mnv[o] = f[L] = oo; else { int M = L + R >> 1, lc = o << 1, rc = lc | 1; build(L, M, lc); build(M+1, R, rc); mnv[o] = min(mnv[lc], mnv[rc]); } return ; } void update( int L, int R, int o, int p, int v) { if (L == R) mnv[o] = f[L] = v; else { int M = L + R >> 1, lc = o << 1, rc = lc | 1; if (p <= M) update(L, M, lc, p, v); else update(M+1, R, rc, p, v); mnv[o] = min(mnv[lc], mnv[rc]); } return ; } int query( int L, int R, int o, int ql, int qr) { if (ql <= L && R <= qr) return mnv[o]; int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = oo; if (ql <= M) ans = min(ans, query(L, M, lc, ql, qr)); if (qr > M) ans = min(ans, query(M+1, R, rc, ql, qr)); return ans; } int Len[maxn]; char Str[maxn], S[maxn]; int main() { while (scanf( "%s" , Str + 1) == 1) { int n = strlen(Str + 1); for ( int i = 1; i <= n; i++) S[i<<1] = Str[i], S[(i<<1)-1] = '#' ; n = n << 1 | 1; S[n] = '#' ; // S[n+1] = '\0'; printf("%s\n", S + 1); int mxi = 0; for ( int i = 1; i <= n; i++) { int mxp = mxi + Len[mxi] - 1; if (mxp < i) Len[i] = 1; else Len[i] = min(Len[(mxi<<1)-i], mxp - i + 1); while (1 <= i - Len[i] + 1 && i + Len[i] - 1 <= n && S[i-Len[i]+1] == S[i+Len[i]-1]) Len[i]++; Len[i]--; if (mxp < i + Len[i] - 1) mxi = i; } build(0, n, 1); update(0, n, 1, 0, -1); for ( int i = 1; i <= n; i++) { int ql = i - Len[i], qr = n; int tmp = query(0, n, 1, ql, qr) + 1; if (tmp < f[i+Len[i]-1]) update(0, n, 1, i + Len[i] - 1, tmp); } printf( "%d\n" , f[n]); } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步