[2019杭电多校第一场][hdu6583]Typewriter(后缀自动机&&dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6583
大致题意是说可以花费p在字符串后添加一个任意字符,或者花费q在字符串后添加一个当前字符串的子串。问最少花费多少可以得到目标串。
一开始想到的dp,dp[i]为得到目标串的1-i的最小花费。
那么dp[i]=min{dp[i-1]+p,dp[j-1]+q},s[j~i]应该为s[1~j-1]的子串。
我们可以知道dp数组是一个单调递增的数组,用反证法可以证明:dp[i]由dp[i-1]转移就不用说了,如果dp[i]是由dp[j]转移过来且dp[i-1]>dp[i],那么dp[i-1]也可以由dp[j]转移过来,所以不合法。
因为dp数组是递增的,则dp[i]如果是由第二种方法转移过来,则j应该是最小的。所以求最小的j满足s[j~i]应该为s[1~j-1]的子串。
dp[i]的第二种转移位置,应该在是dp[i-1]的第二种转移位置j的基础上往后移。
所以用双指针的位置,一个代表i,一个代表j,每次在后缀自动机上添加第j个位置的字符,如果s[j~i]在后缀自动机上可以匹配,则转移,不然就把j往后移。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + ;
const ll inf = 1e18;
struct SAM {
int cnt, last, now;
int len[maxn * ], ch[maxn * ][], fa[maxn * ];
void clear() {
for (int i = ; i <= cnt; i++) {
len[i] = fa[i] = ;
memset(ch[i], , sizeof(ch[i]));
}
}
void insert(int x) {
int np = ++cnt, p = last;
len[np] = len[p] + , last = np;
while (p && !ch[p][x])
ch[p][x] = np, p = fa[p];
if (!p)
fa[np] = ;
else {
int q = ch[p][x];
if (len[q] == len[p] + )
fa[np] = q;
else {
int nq = ++cnt;
len[nq] = len[p] + ;
memcpy(ch[nq], ch[q], sizeof(ch[nq]));
fa[nq] = fa[q];
fa[np] = fa[q] = nq;
while (p&&ch[p][x] == q)
ch[p][x] = nq, p = fa[p];
}
}
}
int Match(int x) {
return ch[now][x];
}
void withdraw(int lens) {
while (now&&len[fa[now]] >= lens)now = fa[now];
if (now == )now = ;
}
void Tran(int x, int lens) {
now = ch[now][x];
if (now == )now = ;
withdraw(lens);
}
}SA;
ll dp[maxn];
char s[maxn];
int main() {
while (~scanf("%s", s + )) {
ll p, q, len;
memset(dp, , sizeof(dp));
scanf("%lld%lld", &p, &q);
len = strlen(s + );
SA.cnt = SA.last = SA.now = ;
SA.insert(s[] - 'a');
dp[] = p;
int l = , r = ;
for (int i = ; i <= len; i++) {
r++;
dp[i] = dp[i - ] + p;
while ((!SA.Match(s[i] - 'a') || r - l + > (i + ) / ) && l <= r) {
SA.insert(s[l++] - 'a');
SA.withdraw(r - l);
}
SA.Tran(s[i] - 'a', r - l + );
if (l <= r)
dp[r] = min(dp[r], dp[l - ] + q);
}
printf("%lld\n", dp[len]);
SA.clear();
} }
[2019杭电多校第一场][hdu6583]Typewriter(后缀自动机&&dp)的更多相关文章
- 2019杭电多校第一场hdu6581 Vacation
Vacation 题目传送门 update(O(n)) 看了那个O(n)的方法,感觉自己想的那个O(nlogn)的好傻,awsl. 0车最终通过停车线的时候,状态一定是某个车堵住后面的所有车(这个车也 ...
- [2019杭电多校第一场][hdu6582]Path(最短路&&最小割)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582 题意:删掉边使得1到n的最短路改变,删掉边的代价为该边的边权.求最小代价. 比赛时一片浆糊,赛后 ...
- [2019杭电多校第一场][hdu6579]Operation(线性基)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6579 题目大意是两个操作,1个是求[l,r]区间子序列的最大异或和,另一个是在最后面添加一个数. 如果 ...
- [2019杭电多校第一场][hdu6578]Blank(dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6578 计数问题想到dp不过分吧... dp[i][j][k][w]为第1-i位置中4个数最后一次出现的 ...
- 2019杭电多校第一场hdu6579 Operation(线性基)
Operation 题目传送门 解题思路 把右边的数尽量往高位放,构造线性基的时候同时记录其在原序列中的位置,在可以插入的时候如果那个位置上存在的数字的位置比新放入的要小,就把旧的往后挤.用这种发现构 ...
- 2018 Multi-University Training Contest 1 杭电多校第一场
抱着可能杭电的多校1比牛客的多校1更恐怖的想法 看到三道签到题 幸福的都快哭出来了好吗 1001 Maximum Multiple(hdoj 6298) 链接:http://acm.hdu.edu. ...
- 2019年杭电多校第一场 1009题String(HDU6586+模拟+单调栈)
题目链接 传送门 题意 给你一个字符串,要你构造一个长为\(k\)的子串使得每个字母出现的次数在\([L_i,R_i](0\leq i\leq26)\)间且字典序最小. 思路 做这种题目就是要保持思路 ...
- 2019年杭电多校第一场 1004题Vacation(HDU6581+数学)
题目链接 传送门 题意 有\(n+1\)辆车要过红绿灯,告诉你车的长度.与红绿灯的起点(题目假设红绿灯始终为绿).车的最大速度,问你第\(0\)辆车(距离最远)车头到达红绿灯起点的时间是多少(每辆车最 ...
- 2019年杭电多校第一场 1002题Operation(HDU6579+线性基)
题目链接 传送门 题意 初始时有\(n\)个数,现在有\(q\)次操作: 查询\([l,r]\)内选择一些数使得异或和最大: 在末尾加入一个数. 题目强制在线. 思路 对于\(i\)我们记录\([1, ...
随机推荐
- java实现一个简单的计数器
package com.fengunion.sf; import org.junit.platform.commons.util.StringUtils; import java.util.HashM ...
- Django【第20篇】:Ajax
初始Ajax 一.Ajax准备知识:json 说起json,我们大家都了解,就是python中的json模块,那么json模块具体是什么呢?那我们现在详细的来说明一下 1.json(Javascrip ...
- 接口返回[object,Object]解决方法
1.我们请求接口时有时会返回[object,Object],[object,Object],[object,Object].... 这个我们使用JSON.stringfity(data),就可以解决.
- Linux技术学习要点,您掌握了吗---初学者必看
1.如何做好嵌入式Linux学习前的准备? 要成为一名合格的嵌入式Linux工程师,就需要系统的学习软.硬件相关领域内的知识,需要在最开始就掌握开发的规范和原则,养成良好的工作习惯.为了确保学习的效果 ...
- STM32内部硬核的认识
STM32内部含有硬核,对于一些协议(例如:UART,SPI,IIC,CRC等)我们只要调用硬核就可以了,同时我们也可以自己写通信协议. 这些硬核最终肯定是要有引脚输出的,这就是为什么STM32的引脚 ...
- 浙大PAT CCCC L3-013 非常弹的球 ( 高中物理题 )
题目链接 题意 : 刚上高一的森森为了学好物理,买了一个“非常弹”的球.虽然说是非常弹的球,其实也就是一般的弹力球而已.森森玩了一会儿弹力球后突然想到,假如他在地上用力弹球,球最远能弹到多远去呢?他不 ...
- Apache编译教程
手工编译安装Apache, 版本httpd-2.4.29(免费提供安装包,懒人福利:提供安装脚本):https://blog.51cto.com/13728740/2158576 编译安装apache ...
- jq和js用法:入口写法
jq和js入口写法demo: <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- str_shuffle函数
str_shuffle() 函数打乱一个字符串,使用任何一种可能的排序方案. <?php $str = 'hello world '; echo str_shuffle($str); ...
- leetcode-mid-Linked list-160 Intersection of Two Linked Lists-NO
mycode 用了反转链表,所以不符合题意 参考: 思路: 1 先让长的链表先走,然后相同长度下看是否相遇 class Solution(object): def getIntersectionNod ...