HDU 6583 Typewriter(后缀自动机)
Typewrite
\]
题意
给出一个字符串 \(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\) 在满足条件范围的节点上。
- 一个问题就是 \(pos\) 何时不能向 \(s[r]\) 方向移动,这种情况就是 \(pos\) 节点不存在 \(s[r]\) 这条边。
 - 令一个问题就是如何维护 \(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(后缀自动机)的更多相关文章
- HDU - 6583 Typewriter (后缀自动机+dp)
		
题目链接 题意:你要打印一段字符串,往尾部添加一个字符需要花费p元,复制一段字符到尾部需要花费q元,求打印完全部字符的最小花费. 一开始想的贪心,后来发现忘了考虑p<q的情况了,还纳闷怎么不对. ...
 - HDU 6583 Typewriter 题解
		
——本题来自杭电多校第一场 题意:给定一个字符串,主角需要用打字机将字符串打出来,每次可以: 1.花费p来打出任意一个字符 2.花费q来将已经打出的某一段(子串)复制到后面去 对于这种最优化的问题,我 ...
 - HDU 4622 Reincarnation 后缀自动机
		
模板来源:http://blog.csdn.net/zkfzkfzkfzkfzkfzkfzk/article/details/9669747 解法参考:http://blog.csdn.net/dyx ...
 - HDU 4622 Reincarnation 后缀自动机 // BKDRHash(最优hash)
		
Reincarnation Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) P ...
 - str2int HDU - 4436 (后缀自动机)
		
str2int \[ Time Limit: 3000 ms\quad Memory Limit: 131072 kB \] 题意 给出 \(n\) 个串,求出这 \(n\) 个串所有子串代表的数字的 ...
 - Reincarnation HDU - 4622 (后缀自动机)
		
Reincarnation \[ Time Limit: 3000 ms\quad Memory Limit: 65536 kB \] 题意 给出一个字符串 \(S\),然后给出 \(m\) 次查询, ...
 - Good Article Good sentence HDU - 4416 (后缀自动机)
		
Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...
 - HDU 4641 K-string 后缀自动机 并查集
		
http://acm.hdu.edu.cn/showproblem.php?pid=4641 https://blog.csdn.net/asdfgh0308/article/details/4096 ...
 - Hdu 4622 Reincarnation(后缀自动机)
		
/* 字符串长度较小, 可以离线或者直接与处理所有区间的答案 动态加入点的时候, 因为对于其他点的parent构造要么没有影响, 要么就是在两个节点之间塞入一个点, 对于minmax的贡献没有改变 所 ...
 
随机推荐
- Lua table的remove函数
			
[1]remove函数简介 table.remove(table, pos): 返回table数组中位于pos位置的元素,其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元 ...
 - 查看电脑已保存的wifi及密码
			
1. 查看以保存的wifi名称 打开cmd(win+r) #查看已保存WiFi名称 netsh wlan show profiles 2. 查看已保存的wifi的密码 netsh wlan show ...
 - English--动名词
			
English|动名词 开始动名词的学习,代表着在长难句的征途上又向前迈出了一步. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的描述.力求不含任何的自我感情色彩. 情感:用 ...
 - .net Core MongoDB用法演示
			
C#驱动MongoDB的本质是将C#的操作代码转换为mongo shell,驱动的API也比较简单明了,方法名和js shell的方法名基本都保持一致,熟悉mongo shell后学习MongoDB的 ...
 - Prometheus 配置文件详解
			
Prometheus 配置文件详解 官方文档:https://prometheus.io/docs/prometheus/latest/configuration/configuration/ 指标说 ...
 - centos lnmp一键安装
			
安装 系统需求: 需要2 GB硬盘剩余空间 128M以上内存,OpenVZ的建议192MB以上(小内存请勿使用64位系统) Linux下区分大小写,输入命令时请注意! 安装步骤: 1.使用putty或 ...
 - tf.assign_add
			
import tensorflow as tf global_step = tf.Variable(1.0, dtype=tf.float64, trainable=False, name='glob ...
 - JavaScript数据类型和语法
			
第一章 类型 1.2 内置类型 使用 typeof 检测对象类型并不是非常安全的行为: // 安全的 typeof undefined // 'undefined' typeof true // 'b ...
 - Vue学习之Webpack小结(十二)
			
一.nrm: nrm是专门用来管理和快速切换私人配置的registry; nrm提供了一些最常用的npm包镜像地址,能够让我们快速的切换安装包时候的服务器地址: 二.镜像: 原来 包 刚一开 ...
 - Vue项目打包发布后CSS中的背景图片不显示
			
相信有很多同学在学习vue的刚开始都遇到过项目打包发布后发现CSS中的背景图片不显示,具体如何解决只需要更改bind的配置即可 修改 build/utils.js 中的 generateLoaders ...