传送门

题意:

给出\(p,q\),现在要你生成一个字符串\(s\)。

你可以进行两种操作:一种是花费\(p\)的代价随意在后面添加一个字符,另一种是花费\(q\)的代价可以随意赋值前面的一个子串。

现在问最小代价是多少。

思路:

考虑\(dp\),那么就有转移方程:\(dp[i]=min\{dp[i-1]+p,dp[j]+q\}\),即直接对两种操作取min即可。

注意到该\(dp\)方程有一个性质:其值肯定为单调不降的。因为如果有\(dp[i-1]>dp[i]\),那此时我们跟着复制过来肯定更好,不能复制就花\(p\)在后面增加,那值岂不是也变大了?

所以转移方程中的\(j\)应为最远的一个\(j\)。

之后思路如下:

  • 考虑维护离当前\(i\)最远的一个\(j\),使得\(s[1,\cdots,j-1]\)的子串中含有\(s[j,\cdots,i]\)。
  • 注意到\(j\)是单调不减的,考虑用后缀自动机来维护这样一个位置。
  • 当向\(i+1\)转移时,若目前后缀自动机中无法成功向\(s[i+1]\)转移,那么将第\(j\)个字符加入后缀自动机并且\(j++\),直到成功转移。
  • 注意我们始终要保证后缀自动机中的状态长度尽可能小,这样我们才能保证\(j\)尽可能远,详见\(withdraw\)操作。

挺好的一道题,需要透彻分析问题的性质。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5;
int p, q;
char s[N];
struct SAM{
struct node{
int ch[26];
int len, fa;
node(){memset(ch, 0, sizeof(ch)), len = 0;}
}dian[N];
int last, tot, now;
void init(int n) {
last = tot = now = 1;
for(int i = 1; i <= 2 * n; i++) {
for(int j = 0; j < 26; j++) dian[i].ch[j] = 0;
dian[i].len = 0;
}
}
void add(int c) {
int p = last;
int np = last = ++tot;
dian[np].len = dian[p].len + 1;
for(; p && !dian[p].ch[c]; p = dian[p].fa) dian[p].ch[c] = np;
if(!p) dian[np].fa = 1;
else {
int q = dian[p].ch[c];
if(dian[q].len == dian[p].len + 1) dian[np].fa = q;
else {
int nq = ++tot; dian[nq] = dian[q];
dian[nq].len = dian[p].len + 1;
dian[q].fa = dian[np].fa = nq;
for(; p && dian[p].ch[c] == q; p = dian[p].fa) dian[p].ch[c] = nq;
}
}
}
void withdraw(int lens) {
while(now && dian[dian[now].fa].len >= lens) now = dian[now].fa;
if(now == 0) now = 1;
}
void trans(int t, int lens) {
now = dian[now].ch[t];
withdraw(lens);
}
bool match(int t) {
return dian[now].ch[t];
}
}A;
ll dp[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
while(cin >> s + 1) {
int n = strlen(s + 1);
cin >> p >> q;
A.init(n);
int l = 2, r = 1;
A.add(s[1] - 'a'); dp[1] = p;
for(int i = 2; i <= n; i++) {
++r; int tmp = s[i] - 'a';
dp[i] = dp[i - 1] + p;
while((!A.match(tmp) || r - l + 1 > i / 2) && l <= r) {
A.add(s[l++] - 'a');
A.withdraw(r - l);
}
A.trans(tmp, r - l + 1);
dp[i] = min(dp[i], dp[l - 1] + q);
}
cout << dp[n] << '\n';
}
return 0;
}

HDU6583:Typewriter(dp+后缀自动机)的更多相关文章

  1. hdu多校第一场 1006 (hdu6583)Typewriter dp/后缀自动机

    题意: 有个打字机,在当前字符串后新加一个字花费p,把当前字符串的一个连续子串拷贝到当前字符串的末尾花费q,给定一个字符串,求用打字机打出这个字符串的最小花费. 题解: 容易想到用dp 记dp[i]为 ...

  2. [2019杭电多校第一场][hdu6583]Typewriter(后缀自动机&&dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6583 大致题意是说可以花费p在字符串后添加一个任意字符,或者花费q在字符串后添加一个当前字符串的子串. ...

  3. BZOJ 2806: [Ctsc2012]Cheat(单调队列优化dp+后缀自动机)

    传送门 解题思路 肯定先要建出来广义后缀自动机.刚开始以为是个二分+贪心,写了一下结果\(20\)分.说一下正解,首先显然\(L_0\)具有单调性,是可以二分的.考虑二分后怎样判合法,对于分割序列很容 ...

  4. BZOJ.4032.[HEOI2015]最短不公共子串(DP 后缀自动机)

    题目链接 1.求A的最短子串,它不是B的子串. 子串是连续的,对B建SAM,枚举起点,在SAM上找到第一个无法匹配点即可.O(n)用SAM能做吗..开始想错了. 2.求A的最短子串,它不是B的子序列. ...

  5. [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机

    由于要找后缀的前缀,所以先用反串建立SAM. link边组成了后缀树. 两个子串的最长公共前缀是LCA的step 树形dp即可. #include<iostream> #include&l ...

  6. codeforces#1120C. Compress String(dp+后缀自动机)

    题目链接: https://codeforces.com/contest/1120/problem/C 题意: 从前往后压缩一段字符串 有两种操作: 1.对于单个字符,压缩它花费$a$ 2.对于末尾一 ...

  7. HDU - 6583 Typewriter (后缀自动机+dp)

    题目链接 题意:你要打印一段字符串,往尾部添加一个字符需要花费p元,复制一段字符到尾部需要花费q元,求打印完全部字符的最小花费. 一开始想的贪心,后来发现忘了考虑p<q的情况了,还纳闷怎么不对. ...

  8. bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 583  Solved: 330[Submit][Statu ...

  9. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

随机推荐

  1. Educational Codeforces Round 59 (Rated for Div. 2) E 区间dp + 状态定义 + dp预处理(分步dp)

    https://codeforces.com/contest/1107/problem/E 题意 给出01字符串s(n<=100),相邻且相同的字符可以同时消去,一次性消去i个字符的分数是\(a ...

  2. Codeforces Round #549 (Div. 2) F 数形结合 + 凸包(新坑)

    https://codeforces.com/contest/1143/problem/F 题意 有n条形如\(y=x^2+bx+c\)的抛物线,问有多少条抛物线上方没有其他抛物线的交点 题解 \(y ...

  3. 洛谷 P5021 [NOIP2018]赛道重建

    洛谷 P5021 [NOIP2018]赛道重建 传送门 思路 思路就是常规的思路,所以就不说了--我就是来记录一下我的\(AC\)之路的,真的是太爽了 没错--我也是一个个打的部分分,最后终于AC的, ...

  4. [LeetCode] 239. Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  5. [LeetCode] 92. Reverse Linked List II 倒置链表之二

    Reverse a linked list from position m to n. Do it in one-pass. Note: 1 ≤ m ≤ n ≤ length of list. Exa ...

  6. JVM学习笔记1

    1.运行时数据结构 2.堆分代 3.垃圾收集器 Parallel Scavenge收集器:新生代称为PSYoungGen,老年代称为ParOldGen,永久代称为Metaspace ParNew收集器 ...

  7. jmeter和ab的对比

    压测比较常用的工具:ab,webbench,jmeter ab和webbench作为shell模式下轻量级的测试工具,ab比webbench功能更多一些 jmeter作为有GUI界面的更高级测试工具 ...

  8. Beta冲刺(4/7)——2019.5.26

    作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Beta冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 队员学号 队 ...

  9. linux录制终端信息并回放

    我们通常会录制桌面环境视频来作为教程使用,但是视频需要大量的存储空间,而终端脚本文件仅仅是一个文本文件,其文件大小不过是KB级别 1, 开始录制终端会话 [root@VM_0_15_centos ~] ...

  10. sql server删除重复记录只保留一条

    今天遇到一个历史导入数据重复的问题,于是要删除重复的记录,一开始想用子查询的方式找到要删除记录的id删除,后来发现DELETE语句可以直接用外连接,这样更加简单,效率也更高. delete sys_p ...