[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. tcp/ip通信中udp头部结构udphdrp->check校验计算

    通过raw socket修改通信数据后,可通过函数 set_udp_checksum1 重新校验计算iph->check值 在http://www.cnblogs.com/dpf-10/p/78 ...

  2. [NOI 2016]优秀的拆分

    Description 题库链接 给你一个长度为 \(n\) 的只含小写字母的字符串 \(S\) ,计算其子串有多少优秀的拆分. 如果一个字符串能被表示成 \(AABB\) 的形式,其中 \(A,B\ ...

  3. [转]解决ssh登录后闲置时间过长而断开连接

    本文转自: 转载自博客园wanghetao的博客 我们通过终端连接服务器时,当鼠标和键盘长时间不操作,服务器就会自动断开连接,我们还的需要重新连接,感觉很麻烦,总结一下解决此问题的方法 方法一 修改/ ...

  4. Linq 处理 List数据

    概述:LINQ又称为语言集成查询,是一种类似于SQL的一种查询语言.语言集成查询让开发人员可以使用.NET程序语言(如C#)去查询数据源,主要数据源为内存中的集合对象.ADO.NET数据集.数据库以及 ...

  5. Java - LinkedList源码分析

    java提高篇(二二)---LinkedList 一.概述 LinkedList与ArrayList一样实现List接口,只是ArrayList是List接口的大小可变数组的实现,LinkedList ...

  6. Codeforces445B(SummerTrainingDay06-N 并查集)

    B. DZY Loves Chemistry time limit per test:1 second memory limit per test:256 megabytes input:standa ...

  7. SPOJ4580 ABCDEF(meet in the middle)

    题意 题目链接 Sol 发现abcdef是互不相关的 那么meet in the middle一下.先算出abc的,再算def的 注意d = 0的时候不合法(害我wa了两发..) #include&l ...

  8. js-权威指南学习笔记19

    第十九章 jQuery类库 1.传递HTML文本字符串给$()方法,jQuery会根据传入的文本创建好HTML元素并封装为jQuery对象返回. 2.想要遍历jQuery对象中的所有元素时,可以调用e ...

  9. JavaScript 数组复制的方法

    1.循环 2.Array.from(arr) 3.let arr2 = [...arr]

  10. 去除img默认的边框

    //当img属性src没有值时,会有难看的边框和难看的一个小图 有什么办法去掉呢? <img  src=" " /> //不要这样写 <img   />  ...