Typewrite

\[Time Limit: 1500 ms\quad Memory Limit: 262144 kB
\]

题意

给出一个字符串 \(s\),现在你需要构造出这个字符串,你每次可以花费 \(q\) 在末尾加上任意一个字符或者花费 \(p\) 复制任意一段已经构造出来的子串到末尾,问最少需要花费多少。

思路

令 \(dp[i]\) 表示构造到第 \(i\) 位最少花费多少。

第一种情况,直接花费 \(q\) 添加在末尾,\(dp[r] = dp[r-1]+q\)

第二种情况,花费 \(p\) 复制一部分到末尾,设 \(s[l+1...r]\) 是被复制的串,那么此时需要满足 \(s[l+1...r] \in s[1...l]\),则 \(dp[r] = dp[l] + p\),此时的问题就是如何维护 \(l\)。

利用后缀自动机可以表示出所有子串的性质,\(pos\) 表示满足条件的 \(s[l+1...r]\) 所在后缀自动机上的节点位置。

每次插入 \(s[r]\) 时,就是从 \(s[l+1...r-1]\in s[1...l] \implies s[l+1...r] \in s[1...l]\) 的过程,所以要让 \(pos\) 节点往 \(s[r]\) 方向移动。如果能移动的话,直接将 \(pos\) 移动过去,否则就扩展这个自动机,将 \(s[l]\) 插入后在尝试能否移动。在这个过程中,不断维护 \(pos\) 在满足条件范围的节点上。

  1. 一个问题就是 \(pos\) 何时不能向 \(s[r]\) 方向移动,这种情况就是 \(pos\) 节点不存在 \(s[r]\) 这条边。
  2. 令一个问题就是如何维护 \(pos\) 在符合条件的范围内,我们知道 \(pos\) 节点包含了同样性质的长度从 \(len[fa[pos]]+1\) 到 \(len[pos]\) 内的子串,我们只要保证这里面最短的子串 \(len[fa[pos]]+1\) 不要太长,需要可以表示出后面那部分的串。在插入 \(s[r]\) 之前,此时只到 \(r-1\),需要保证 \(len[fa[pos]]+1 \leq (r-1)-(l+1)+1\),插入 \(s[r]\) 后,此时到了 \(r\),需要保证 \(len[fa[pos]]+1 \leq r-(l+1)+1\)
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout) typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 2e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std; int n, m;
int cas, tol, T; struct Sam {
int node[maxn<<1][27], fa[maxn<<1], step[maxn<<1];
int sz, last;
int newnode() {
mes(node[++sz], 0);
fa[sz] = step[sz] = 0;
return sz;
}
void init() {
sz = 0;
last = newnode();
}
void insert(int k) {
int p = last, np = last = newnode();
step[np] = step[p]+1;
for(; p&&!node[p][k]; p=fa[p])
node[p][k] = np;
if(p == 0) {
fa[np] = 1;
} else {
int q = node[p][k];
if(step[q] == step[p]+1) {
fa[np] = q;
} else {
int nq = newnode();
for(int i=1; i<=26; i++)
node[nq][i] = node[q][i];
fa[nq] = fa[q];
step[nq] = step[p]+1;
fa[np] = fa[q] = nq;
for(; p&&node[p][k]==q; p=fa[p])
node[p][k] = nq;
}
}
}
} sam;
char s[maxn];
ll dp[maxn]; int main() {
while(~scanf("%s", s+1)) {
sam.init();
int len = strlen(s+1);
ll p, q;
scanf("%lld%lld", &q, &p);
ll ans = 0;
int l=0, pos=0;
dp[0] = 0;
for(int r=1; r<=len; r++) {
dp[r] = dp[r-1]+q;
int k = s[r]-'a'+1;
while(!sam.node[pos][k]) {
sam.insert(s[++l]-'a'+1);
while(pos && sam.step[sam.fa[pos]]>r-l-2)
pos = sam.fa[pos];
if(!pos) pos = 1;
}
pos = sam.node[pos][k];
while(pos && sam.step[sam.fa[pos]]>r-l-1)
pos = sam.fa[pos];
if(!pos) pos = 1;
dp[r] = min(dp[r], dp[l]+p);
}
printf("%lld\n", dp[len]);
}
return 0;
}

HDU 6583 Typewriter(后缀自动机)的更多相关文章

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

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

  2. HDU 6583 Typewriter 题解

    ——本题来自杭电多校第一场 题意:给定一个字符串,主角需要用打字机将字符串打出来,每次可以: 1.花费p来打出任意一个字符 2.花费q来将已经打出的某一段(子串)复制到后面去 对于这种最优化的问题,我 ...

  3. HDU 4622 Reincarnation 后缀自动机

    模板来源:http://blog.csdn.net/zkfzkfzkfzkfzkfzkfzk/article/details/9669747 解法参考:http://blog.csdn.net/dyx ...

  4. HDU 4622 Reincarnation 后缀自动机 // BKDRHash(最优hash)

    Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) P ...

  5. str2int HDU - 4436 (后缀自动机)

    str2int \[ Time Limit: 3000 ms\quad Memory Limit: 131072 kB \] 题意 给出 \(n\) 个串,求出这 \(n\) 个串所有子串代表的数字的 ...

  6. Reincarnation HDU - 4622 (后缀自动机)

    Reincarnation \[ Time Limit: 3000 ms\quad Memory Limit: 65536 kB \] 题意 给出一个字符串 \(S\),然后给出 \(m\) 次查询, ...

  7. Good Article Good sentence HDU - 4416 (后缀自动机)

    Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...

  8. HDU 4641 K-string 后缀自动机 并查集

    http://acm.hdu.edu.cn/showproblem.php?pid=4641 https://blog.csdn.net/asdfgh0308/article/details/4096 ...

  9. Hdu 4622 Reincarnation(后缀自动机)

    /* 字符串长度较小, 可以离线或者直接与处理所有区间的答案 动态加入点的时候, 因为对于其他点的parent构造要么没有影响, 要么就是在两个节点之间塞入一个点, 对于minmax的贡献没有改变 所 ...

随机推荐

  1. C编程遇到的一些小细节

    1  typedef int ElemType  -->  typedef int ElemType; 此处要加分行(:),要区别  #defin a 20 此处不需要加分号:#define是预 ...

  2. golang知识精要(二)

    类型 go是**静态类型**语言,不能在运行期改变变量类型. 变量定义 使用var定义变量,自动初始化为零值: 如果提供初始值,可省略变量类型: 函数内部可使用:=定义变量. var x int // ...

  3. 红黑树和AVL树的区别(转)

    add by zhj: AVL树和红黑树都是平衡二叉树,虽然AVL树是最早发明的平衡二叉树,但直接把平衡二叉树等价于AVL树,我认为非常不合适. 但很多地方都在这么用.两者的比较如下 平衡二叉树类型 ...

  4. golang学习笔记--接口

    go 的接口类型用于定义一组行为,其中每个行为都由一个方法声明表示. 接口类型中的方法声明只有方法签名而没有方法实体,而方法签名包括且仅包括方法的名称.参数列表和结果列表. 只要一种数据类型的方法集合 ...

  5. kubenetes之配置pod的QoS

    系列目录 上节提到过,QoS影响pod的调度和驱离,本节讲解如何通过配置pod来使它自动被赋予一个QoS 实际上是pod的配置达到一定标准,则kubernetes会自动为其它添加一个QoS类 QoS类 ...

  6. 计数计量单位KMGTPEZY【计算机】【天文】

    · Bit = Binary Digit · Bits = · s = Kilo · Kilo s = Mega · Mega s = Giga · Giga s = Tera · Tera s = ...

  7. [K8s 1.9实践]Kubeadm 1.9 HA 高可用 集群 本地离线镜像部署

    k8s介绍 k8s 发展速度很快,目前很多大的公司容器集群都基于该项目,如京东,腾讯,滴滴,瓜子二手车,北森等等. kubernetes1.9版本发布2017年12月15日,每是那三个月一个迭代, W ...

  8. opencv简单卷积运用

    import cv2 as cv import numpy as np img=cv.imread('learn.jpg',cv.IMREAD_GRAYSCALE) cv.imshow('first ...

  9. 2019-08-01 jquery中常用方法

    1.attr()方法设置或返回被选元素的属性值 <html> <meta charset="utf-8"/> <head><title&g ...

  10. js多个参数(追加参数)

    /** * 多个参数 * @param fn * @param args * @param scope */ function multipleArguments(fn,args,scope){ if ...