[luogu T71973]卡常者π酱
[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]卡常者π酱的更多相关文章
- bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增
bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...
- [luogu1972][bzoj1878][SDOI2009]HH的项链【莫队+玄学卡常】
题目大意 静态区间查询不同数的个数. 分析 好了,成功被这道题目拉低了AC率... 打了莫队T飞掉了,真的是飞掉了QwQ. 蒟蒻想不出主席树的做法,就换成了莫队... 很多人都不知道莫队是什么... ...
- BZOJ3286 Fibonacci矩阵 矩阵 快速幂 卡常
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3286 题意概括 n,m,a,b,c,d,e,f<=10^1000000 题解 神奇的卡常题目 ...
- 【xsy1120】 支援(assist) dp+卡常
妙啊算错时间复杂度了 题目大意:给你一棵$n$个节点的二叉树,每个节点要么是叶子节点,要么拥有恰好两个儿子. 令$m$为叶子节点个数,你需要在这棵二叉树中选择$i$个叶子节点染色,叶节点染色需要一定的 ...
- BZOJ1878 [SDOI2009] HH的项链 [莫队,卡常]
BZOJ传送门,洛谷传送门 HH的项链 Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一 段贝壳,思考它们所表达的含义. ...
- 【卡常 bitset 分块】loj#6499. 「雅礼集训 2018 Day2」颜色
好不容易算着块大小,裸的分块才能过随机极限数据:然而这题在线的数据都竟然是构造的…… 题目描述 有 $n$ 个数字,第 $i$ 个数字为 $a_i$. 有 $m$ 次询问,每次给出 $k_i$ 个区间 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常
Description 方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题. Oj上注册了n个用户,编号为1-”,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和 ...
- [SPOJ] DIVCNT2 - Counting Divisors (square) (平方的约数个数前缀和 容斥 卡常)
题目 vjudge URL:Counting Divisors (square) Let σ0(n)\sigma_0(n)σ0(n) be the number of positive diviso ...
- 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 ...
随机推荐
- UVa 10562 Undraw the Trees(递归遍历)
题目链接: https://cn.vjudge.net/problem/UVA-10562 Professor Homer has been reported missing. We suspect ...
- Quartz2D指定显示范围
在qq中,可以看到头像是圆形显示的,通过CGContextClip可以设置 CGContextRef context=UIGraphicsGetCurrentContext(); CGContextA ...
- [转]SQL Server 2008 如何配置报表管理器
本文转自:https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/cc281384%28v%3dsql.100%2 ...
- Jquery操作样式
1.CSS(name,value) 修改单个样式 $(function(){ $(".divcontent").css("background","r ...
- WinForm窗体上两个panel,怎么实现一个panel固定漂浮在另一个panel之上
问题:winform窗体,要实现一个panel漂浮在另一个panel之上,但是运行的时候移动鼠标或者其他操作,上面那个panel就会消失?即只能显示一个panel. 原因:在窗体上拖放控件肉眼观察是平 ...
- winform窗体 小程序【打开多个窗体、窗体之间传值、打开唯一窗体】
1.打开多个窗体 2.窗体之间的传值 3打开唯一窗体
- c#里面如何激活一个外部程序进程并显示在最前
using System.Diagnostics; using System.Runtime.InteropServices; [DllImport("user32.dll")] ...
- 几点建议,让Redis在你的系统中发挥更大作用
Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储:它的数据模型非常独特,用的是单线程.另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不 ...
- C# 免客户端访问Oracle的DLL
代码示例: OracleConnection con = new OracleConnection(); con.ConnectionString ="user ...
- avalonjs 实现简单购物车
因为最近有在做购物车,然后我们是用avalon来实现一些模块的,所以顺其自然的用avalon来实现购物车,目前发现avalon还是比较强大的,大大的节约了代码量. 购物车一般具备的功能是加减数量.选择 ...