[luogu T71973]卡常者π酱

题意

给定一个长度为 \(n\) 的字符串, 要求将字符串分割为若干段, 每一段要么是一个字符要么是前面几段的并的子串.

如果某一段是一个单独字符, 则产生 \(a\) 的开销.

如果是前几段的并的子串, 则产生 \(b\) 的开销.

如果满足两个条件, 则可以在 \(a,b\) 中任选一个开销.

求划分的最小开销.

\(n\le 5\times 10^6\), 字符集大小 \(\Sigma\le 7\).

题解

冷静分析一下发现是沙雕题

然而题目说不卡常实际上是真的卡常...严格 \(O(n)\) 并不一定能跑过...

我们发现这个沙雕题最后一个串的开销和前面的划分方案无关, 果断想到DP. 设 \(dp_i\) 表示长度为 \(i\) 的前缀的最小划分代价.

然后有个显然的性质, 就是如果有一个后缀满足它在前面出现过, 那么这个后缀的所有后缀同样都满足. 所以不难想到对于当前DP前缀找到满足该性质的最长的后缀, 然后在这个后缀的所有后缀中找最小DP值更新.

不难发现这个过程实际上可以用后缀自动机解决. 对于每个状态都维护一下 \(right\) 集合中的最小值, 也就是当前状态所代表字符串的第一次出现的右端点的位置. 这样我们就可以直接知道当前后缀是否在前面出现过了.

不难发现这个后缀的左端点位置也是单调的, 所以不合法暴力跳就可以 \(O(n)\) 了.

按照刚刚的讨论我们需要把所有合法的后缀的 \(dp\) 值取 \(\min\), 需要单调队列来维护. 但是实际上不难发现 \(dp\) 值是单调不降的, 所以直接取最长合法后缀的左端点处的 \(dp\) 值就可以了.

但是要想A这题还得加点优化. 一个是 \(right\) 集合的最小值的维护, 并不需要给后缀自动机结点基数排序. 因为每次插入的新点的 \(right\) 集合中的值实际上是单调递增的, 而且如果在原来自动机上某个点在另一个点的子树中的话扩展后一定还在那个点的子树里. 所以可以边构造边算.

其次是我们并不需要先构造出整个SAM然后再跑, 我们完全可以边构造边计算最长满足条件的后缀. 因为后面的字符串并不会影响前面已有的信息.

加了这两个优化才卡时限过的...这可真蠢.

(不难分析得到不加两个优化+单调队列实际上也是严格 \(O(n)\) 的时间复杂度)

参考代码

#include <bits/stdc++.h>

const int MAXN=1e7+10;
typedef long long intEx; int n;
int a;
int b;
int cnt=1;
int last=1;
int root=1;
int s[MAXN];
int buc[MAXN];
int len[MAXN];
int prt[MAXN];
int minr[MAXN];
char str[MAXN];
intEx dp[MAXN];
int chd[MAXN][7]; void Extend(char); int main(){
scanf("%d%d%d",&n,&a,&b);
scanf("%s",str+1);
int cur=root,curlen=0;
for(int i=1;i<=n;i++){
Extend(str[i]);
int p=str[i]-'a';
while(!chd[cur][p]){
cur=prt[cur];
curlen=len[cur];
}
++curlen;
cur=chd[cur][p];
while(cur!=root&&minr[cur]>i-curlen){
if(i-minr[cur]>len[prt[cur]])
curlen=i-minr[cur];
else{
cur=prt[cur];
curlen=len[cur];
}
}
dp[i]=dp[i-1]+a;
if(curlen)
dp[i]=std::min(dp[i],dp[i-curlen]+b);
}
printf("%lld\n",dp[n]);
return 0;
} void Extend(char ch){
int x=ch-'a';
int p=last;
int np=++cnt;
last=np;
minr[np]=len[np]=len[p]+1;
while(p&&!chd[p][x])
chd[p][x]=np,p=prt[p];
if(!p)
prt[np]=root;
else{
int q=chd[p][x];
if(len[q]==len[p]+1)
prt[np]=q;
else{
int nq=++cnt;
memcpy(chd[nq],chd[q],sizeof(chd[q]));
len[nq]=len[p]+1;
prt[nq]=prt[q];
prt[q]=nq;
prt[np]=nq;
minr[nq]=minr[q];
while(p&&chd[p][x]==q)
chd[p][x]=nq,p=prt[p];
}
}
}

[luogu T71973]卡常者π酱的更多相关文章

  1. bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增

    bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...

  2. [luogu1972][bzoj1878][SDOI2009]HH的项链【莫队+玄学卡常】

    题目大意 静态区间查询不同数的个数. 分析 好了,成功被这道题目拉低了AC率... 打了莫队T飞掉了,真的是飞掉了QwQ. 蒟蒻想不出主席树的做法,就换成了莫队... 很多人都不知道莫队是什么... ...

  3. BZOJ3286 Fibonacci矩阵 矩阵 快速幂 卡常

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3286 题意概括 n,m,a,b,c,d,e,f<=10^1000000 题解 神奇的卡常题目 ...

  4. 【xsy1120】 支援(assist) dp+卡常

    妙啊算错时间复杂度了 题目大意:给你一棵$n$个节点的二叉树,每个节点要么是叶子节点,要么拥有恰好两个儿子. 令$m$为叶子节点个数,你需要在这棵二叉树中选择$i$个叶子节点染色,叶节点染色需要一定的 ...

  5. BZOJ1878 [SDOI2009] HH的项链 [莫队,卡常]

    BZOJ传送门,洛谷传送门 HH的项链 Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一 段贝壳,思考它们所表达的含义. ...

  6. 【卡常 bitset 分块】loj#6499. 「雅礼集训 2018 Day2」颜色

    好不容易算着块大小,裸的分块才能过随机极限数据:然而这题在线的数据都竟然是构造的…… 题目描述 有 $n$ 个数字,第 $i$ 个数字为 $a_i$. 有 $m$ 次询问,每次给出 $k_i$ 个区间 ...

  7. BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常

    Description 方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题. Oj上注册了n个用户,编号为1-”,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和 ...

  8. [SPOJ] DIVCNT2 - Counting Divisors (square) (平方的约数个数前缀和 容斥 卡常)

    题目 vjudge URL:Counting Divisors (square) Let σ0(n)\sigma_0(n)σ0​(n) be the number of positive diviso ...

  9. CH5102/SPOJ?? Mobile Service/P4046 [JSOI2010]快递服务[线性dp+卡常]

    http://contest-hunter.org:83/contest/0x50%E3%80%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E3%80%8D%E4%B ...

随机推荐

  1. 传统项目转前端工程化——路由跳转时出现浏览器锁死和白屏【该死的同步ajax】

    [一开始我想到是该死的同步ajax,但我没验证,把他忽略了] 在探索前端工程化vue-cli做spa时,从搜索结果页跳转商品详情页时,因为详情页有很多ajax请求,并且都用的同步请求,就会导致请求时浏 ...

  2. .39-浅析webpack源码之parser.parse

    因为换了个工作,所以博客停了一段时间. 这是上个月留下来的坑,webpack的源码已经不太想看了,又臭又长,恶心的要死,想去看node的源码……总之先补完这个 上一节完成了babel-loader对J ...

  3. WPF备忘录(5)怎样修改模板中的控件

    首先,想问大家一个问题,你们如果要给一个Button添加背景图片会怎么做?(呵呵,这个问题又点小白哈) 是这样吗? <Button Height="57" Horizonta ...

  4. SQL 获取时间格式

    2018-12-17 22:31:01  SQL    :  CONVERT(varchar(100), GETDATE(), 20) Oracle:   to_date(SYSDATE(),'yyy ...

  5. 2017.12.21-JQuery

    作业:密码加强验证 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> & ...

  6. [android] 优酷环形菜单-相对布局练习

    优酷环形菜单 布局文件,使用<RelativeLayout/>控件作为第一级菜单,相对布局,位于父控件的底部,水平居中,因为图片不是特别的标准,因此宽度和高度都钉死,宽度是高度的两倍 二次 ...

  7. Android-Handler使用姿势

    http://www.jianshu.com/p/8e9a54f1826e 好文章先马,慢慢看

  8. AutoMapper在项目中的应用

    一.先说说DTO DTO是个什么东东? DTO(Data Transfer Object)就是数据传输对象,说白了就是一个对象,只不过里边全是数据而已. 为什么要用DTO? 1.DTO更注重数据,对领 ...

  9. C++ 的那些坑 (Day 1)

    永远的溢出 运算溢出 溢出是一个永恒的话题. int a = 0xf000; int b = 0xff000; long c = a * b; 此时c = -251658240,以为已经使用了long ...

  10. DataTable的数据或表结构复制

    把datatable的结构全部数据或部分数据复制到一个新的datatabledatatable复制表结构:我们可以使用.clone()方法: DataTable oldDT = GetDataTabl ...