CF825F - String Compression
题意:压缩字符串,把字符串分成若干个子串,每个子串可以被压缩成“循环次数 \(+\) 循环节”的形式,求最小长度。
dp 求 lcp
先 \(O(n^2)\) dp 求出所有后缀对的 \(lcp_{x,y}\),(也可以 \(\text{SA}\) \(O(\log n)\) 求,但是本题 \(n=8000\) 还有 \(\dfrac{1}{2}\) 的常数,没必要这么做。
然后我们设 \(dp_{i}\) 表示当前 \(i-1\) 前面的位置都已经压缩完成的最小长度。枚举最小循环节长度 \(j\),一直往后 \(dp\),直到 \(lcp_{i,r}\lt j\) 为止。
对其中所有的 \(i+kj\),将 \([i,i+kj-1]\) 压缩成一个子串进行转移,转移到 \(i+kj\)。提前预处理出每个循环次数和字符串长度的对应关系 \(O(1)\) 转移到 \(i+kj\),转移复杂度 \(O(n\log n)\),总的复杂度是 \(O(n^2\log n)\) 的,但是常数较小,可过。
双模哈希
首先,显而易见的贪心,如果当前确定了要把 \([l,r]\) 压缩成一个子串,则一定选择最小的循环节。因为选择更大的循环节,循环节的长度增加是循环次数长度减少的 \(10\) 倍。
然后,考虑如何计算 \([l,r]\) 中的最小循环节。
我们考虑计算 \(f_{l,r}\) 表示以 \([l,r]\) 为第一个循环节,最多往后循环次数。我们可以从后往前枚举左端点,然后只考虑 \(f_{r+1,r+(r-l+1)}\),因为这是我们从 \(f_{l,r}\) 往后拓展的必经之路。我们可以用字符串哈希 \(O(1)\) 判断两个区间是否相等,从而判断能否从后面进行转移,如果可以,\(f_{l,r}=f_{r+1,r+(r-l+1)}+1\),否则,\(f_{l,r}=1\)。
接下来有一个假做法,就是枚举 \(i\) 之后的最小循环节长度,然后贪心选取尽可能多的循环次数。但是这样会 WA,因为我们可能要留一点字符给后面的循环节。
我们考虑计算 \(g_{l,r}\) 表示 \([l,r]\) 的最小循环节。我们的思路是从小到大枚举,然后使用 \(f_{l,r}\) 往后延申直到超出 \(f_{l,r}\) 的次数。这样就是对每个 \([l,r]\) 都循环 \(f_{l,r}\) 次对 \(g_{l,l+k\times len}\) 进行贡献。复杂度是 \(O(n^2\log n)\),和前面的做法没什么区别。
但是我们如果使用一些线性筛的思想,使得每个 \(g_{l,r}\) 只被自己的最小循环节贡献,如果当前的循环节已经存在循环节,就不往更大的区间进行贡献。我们发现这是正确的。
首先,如果一个长度 \(n\) 的区间存在两种循环节,长度分别是 \(x\) 和 \(y\),那么一定存在 \(\gcd(x,y)\) 长度的循环节。我们假设 \(x<y\),考虑所有长度为 \(y\) 的循环节将所有长为 \(\gcd(x,y)\) 的单元分成 \(n/y\) 段,每段都有 \(y\) 个不同的,而划分出 \(y\) 个剩余类,例如 0 1 2 0 1 2 0 1 ...
。然后考虑 \(x\) 对 \(y\) 的覆盖,因为 \(x'=\dfrac{x}{\gcd(x,y)}\) 和 \(y'=\dfrac{y}{\gcd(x,y)}\) 是互质的,所以其唯一重合的地方是 \(n'=\dfrac{n}{\gcd(x,y)}\)。那么从 \(0\) 开始每次跳 \(x'\) 遍历可以遍历 \(y'\) 的整个剩余系。
或者说,对 \(y'\) 的剩余系而言,因为 \(x'\) 和 \(y'\) 互质,所以设 \(S\) 是模 \(y\) 的剩余系,则 \(xS=S\),即\(0,x',2x',3x',\cdots,(y'-1)x'\) 模 \(y'\) 两两不同余。则所有模 \(x'\) 意义下的等价类 \(0\) 都两两不同的对应了模 \(y\) 意义下的所有等价类恰好一次,得到所有 \(\gcd(x,y)\) 长的单元都是相同的,则存在长度 \(\gcd(x,y)\) 的循环节。
那么,任何的区间 \([l,r]\) 都存在唯一最小的循环节 \(s\),使得任意其他循环节 \(t\),都存在 \(k|s|=|t|\)。那么在 \(s\) 贡献到 \([l,r]\) 的同时,其其他循环节也都被贡献到了,由于先枚举小的区间,我们就不会调用 \([l,r]\) 的任意其他循环节覆盖别人,所以计算 \(g_{l,r}\) 的过程中,每个\([l,r]\) 只被扫到一次,总复杂度 \(O(n^2)\)。
最后,设 \(dp_i\) 表示 \(i-1\) 以前都成功配对,然后枚举当前压缩的大区间右端点 \(r\),使用其最小循环节进行贡献,预处理每个数字对应的长度,就可以做到 \(O(1)\) 计算单个转移,总的转移是 \(O(n)\) 的,这一环节的复杂度也是 \(O(n^2)\)。
从而,整个算法的复杂度是 \(O(n^2)\)。注意哈希和匹配的常数较大,可能成为算法瓶颈(大常数 \(O(n^2)\))
const ll P1=998244353,P2=1000000007,S1=114,S2=191;
ll h1[8005],h2[8005],pw1[8005],pw2[8005],ipw1[8005],ipw2[8005];
int cnt[8005][8005],bit[8005],dp[8005];
int f[8005][8005];
st s;int n;
inline pll hsh(int l,int r){
ll r1=(h1[r]-h1[l-1]*pw1[r-l+1]%P1+P1)%P1;
ll r2=(h2[r]-h2[l-1]*pw2[r-l+1]%P2+P2)%P2;
return pll(r1,r2);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>s;n=s.size();s='$'+s;
rp(i,n)h1[i]=(h1[i-1]*S1+s[i]-'a')%P1;
rp(i,n)h2[i]=(h2[i-1]*S2+s[i]-'a')%P2;
pw1[0]=pw2[0]=ipw1[0]=ipw2[0]=1;
rp(i,n)pw1[i]=pw1[i-1]*S1%P1;
rp(i,n)pw2[i]=pw2[i-1]*S2%P2;
rep(i,1,9)bit[i]=1;
rep(i,10,99)bit[i]=2;
rep(i,100,999)bit[i]=3;
rep(i,1000,8000)bit[i]=4;
per(l,1,n)rep(r,l,n){
int len=r-l+1;cnt[l][r]=1;
if(r+len<=n&&hsh(l,r)==hsh(r+1,r+len))cnt[l][r]=cnt[r+1][r+len]+1;
}
dp[1]=0;
rep(i,2,n+1)dp[i]=1e9;
rep(l,1,n)rep(r,l,n)if(f[l][r]==0){
int len=r-l+1;
for(int i=1;l+i*len-1<=n&&i<=cnt[l][r];i++){
f[l][l+i*len-1]=i;
}
}
rep(l,1,n)rep(r,l,n)
dp[r+1]=min(dp[r+1],dp[l]+bit[f[l][r]]+(r-l+1)/f[l][r]);
cout<<dp[n+1]<<endl;
return 0;
}
//Crayan_r
CF825F - String Compression的更多相关文章
- CF825F String Compression 解题报告
CF825F String Compression 题意 给定一个串s,其中重复出现的子串可以压缩成 "数字+重复的子串" 的形式,数字算长度. 只重复一次的串也要压. 求压缩后的 ...
- UVA 1351 十三 String Compression
String Compression Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit ...
- 【leetcode】443. String Compression
problem 443. String Compression Input ["a","a","b","b"," ...
- 443. String Compression
原题: 443. String Compression 解题: 看到题目就想到用map计数,然后将计数的位数计算处理,这里的解法并不满足题目的额外O(1)的要求,并且只是返回了结果array的长度,并 ...
- 213. String Compression【LintCode java】
Description Implement a method to perform basic string compression using the counts of repeated char ...
- 213. String Compression【easy】
Implement a method to perform basic string compression using the counts of repeated characters. For ...
- codeforces 825F F. String Compression dp+kmp找字符串的最小循环节
/** 题目:F. String Compression 链接:http://codeforces.com/problemset/problem/825/F 题意:压缩字符串后求最小长度. 思路: d ...
- Codeforces 825F - String Compression
825F - String Compression 题意 给出一个字符串,你要把它尽量压缩成一个短的字符串,比如一个字符串ababab你可以转化成3ab,长度为 3,比如bbbacacb转化成3b2a ...
- 区间DP UVA 1351 String Compression
题目传送门 /* 题意:给一个字符串,连续相同的段落可以合并,gogogo->3(go),问最小表示的长度 区间DP:dp[i][j]表示[i,j]的区间最小表示长度,那么dp[i][j] = ...
- LeetCode_443. String Compression
443. String Compression Easy Given an array of characters, compress it in-place. The length after co ...
随机推荐
- [信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取
[信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取 实体关系,实体属性抽取是信息抽取的关键任务:实体关系抽取是指从一段文本中抽取关系三元组,实体属性抽取是指从一段文本中抽取属性三元组: ...
- <一>C++ STL
STL (standard template libaray - 标准模板库):是 C++ 标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架. 通俗来说:STL就 ...
- STM32按键控制LED亮灭的代码
led.c #include "led.h" void LED_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2P ...
- uniapp 微信小程序 根据经纬度解析地址(腾讯地图)
//引入腾旭地图sdk import QQMapWX from '../../common/qqmap-wx-jssdk.js' onLoad(){ this.getMapAddress() }, m ...
- 前端使用工具规范commit信息
前言 通过工具规范git提交信息也是工程化的一部分,在前端领域有一些工具为我们提供了相关功能,在这里做一下使用总结. commitlint commitlint是什么? 就像eslint用来检查js代 ...
- [OpenCV实战]1 基于深度学习识别人脸性别和年龄
目录 1基于CNN的性别分类建模原理 1.1 人脸识别 1.2 性别预测 1.3 年龄预测 1.4 结果 2 代码 参考 本教程中,我们将讨论应用于面部的深层学习的有趣应用.我们将估计年龄,并从单个图 ...
- 前菜--Numpy
import numpy as np NumPy : numberial python NumPy的核心:数据结构 ndarray 1.1 数组方法 np.array 创建数组 基本语法:np.arr ...
- 【Surface Detection】Segmentation-Based Deep-Learning Approach for Surface-Defect Detection
物体表面缺陷检测现状 传统机器学习局限性 传统机器学习方法对于特定的算法只能解决特定的问题,不够灵活,无法快速适应新产品: 不同的问题有不同的特征,当需要解决新问题时,需要重新设计特征,开发周期长: ...
- 8. 字符串转整数 (atoi)
题目 代码 class Solution { public: int myAtoi(string str) { int res=0,sign=1; int i=str.find_first_not_o ...
- Loj 507 接竹竿 题解
Loj链接:接竹竿 $ {\scr \color {SkyBlue}{\text{Solution}}} $ 题目大意: 给定一个数组,每次加入一种颜色的数,可以取走与它颜色相同的两个数之间的所有数, ...