https://codeforces.com/contest/1121/problem/F

题意

给你一个有n(<=5000)个字符的串,有两种压缩字符的方法:

1. 压缩单一字符,代价为a

2. 压缩一个串,条件是这个串是前面整个串的连续子串,代价为b

题解

  • n<=5000
  • 定义dp[i]为压缩前i个字符的代价,则答案为dp[n]
  • dp[i]=min(dp[i-1]+a,min(dp[j]+b)(即[j+1,i]为[1,j]的子串))
  • 用字符串哈希处理判定一个串是否为前面的子串

坑点

  • 串abab,如何判定后面一个ab是前面ab的子串?

    • 照旧给每一个位置加权
    • 判定的时候,首先将权值加到同一个权级再比较

      比如存在一个首字符在i和一个首字符在j的串,那么比较的时候哈希值分别都要乘以(size-i)和(size-j),得到权级都是size的串

  • 两层for已经是n*n复杂度,还需要判定后面的串是否是前面串的子串?
    • 一开始想法就是用一个map[i]记录每个位置之前哈希值的出现次数,但是会超内存
    • 换一个\(n*n*log(n)\)的算法,二分找出最小的位置\(log(n)\),枚举前面每一个位置固定长度串\(n\)

代码

#include<bits/stdc++.h>
#define P 47 //加权的质数较小
#define mod 1000000003 //哈希表的质数较大
#define ll long long
using namespace std;
int n,a,b,i,j,sum[5005],dp[5005],pw[6000],l,mid,r;
char s[5005]; void init(){
pw[0]=1;
for(int i=1;i<=n+100;i++)
pw[i]=(ll)pw[i-1]*P%mod;
for(int i=1;i<=n;i++)
sum[i]=(sum[i-1]+(ll)pw[i]*(s[i]-'a'+1)%mod)%mod;
} int geths(int i,int j){
return (int)(((ll)sum[j]-sum[i-1]+mod)%mod*pw[n+50-i]%mod);
} int ck(int p,int i,int j,int len){
int hs=geths(i,j);
for(int k=1;k<=p-len+1;k++){
if(geths(k,k+len-1)==hs)return 1;
}
return 0;
} int main(){
cin>>n>>a>>b;
scanf("%s",s+1);
init();
dp[0]=0;
for(i=1;i<=n;i++){
dp[i]=dp[i-1]+a;
l=1;r=i-1;
while(l<r){
mid=(l+r)/2;
if(ck(i-mid,i-mid+1,i,mid))l=mid+1;
else r=mid;
}
while(!ck(i-l,i-l+1,i,l))l--;
if(l>=1)dp[i]=min(dp[i-l]+b,dp[i]);
}
cout<<dp[n];
}

Codeforces Round #543 (Div. 2) F dp + 二分 + 字符串哈希的更多相关文章

  1. Codeforces Round #486 (Div. 3) F. Rain and Umbrellas

    Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/co ...

  2. Codeforces Round #501 (Div. 3) F. Bracket Substring

    题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60 ...

  3. Codeforces Round #499 (Div. 1) F. Tree

    Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...

  4. Codeforces Round #485 (Div. 2) F. AND Graph

    Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...

  5. Codeforces Round #479 (Div. 3) F. Consecutive Subsequence (简单dp)

    题目:https://codeforces.com/problemset/problem/977/F 题意:一个序列,求最长单调递增子序列,但是有一个要求是中间差值都是1 思路:dp,O(n)复杂度, ...

  6. Codeforces Round #552 (Div. 3) F. Shovels Shop (前缀和预处理+贪心+dp)

    题目:http://codeforces.com/contest/1154/problem/F 题意:给你n个商品,然后还有m个特价活动,你买满x件就把你当前的x件中最便宜的y件价格免费,问你买k件花 ...

  7. Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】

    传送门:http://codeforces.com/contest/1092/problem/F F. Tree with Maximum Cost time limit per test 2 sec ...

  8. Codeforces Round #531 (Div. 3) F. Elongated Matrix(状压DP)

    F. Elongated Matrix 题目链接:https://codeforces.com/contest/1102/problem/F 题意: 给出一个n*m的矩阵,现在可以随意交换任意的两行, ...

  9. Codeforces Round #530 (Div. 2) F 线段树 + 树形dp(自下往上)

    https://codeforces.com/contest/1099/problem/F 题意 一颗n个节点的树上,每个点都有\(x[i]\)个饼干,然后在i节点上吃一个饼干的时间是\(t[i]\) ...

随机推荐

  1. 安卓操作系统版本(Version)与应用程序编程接口等级(Application Programming Interface Level)对照表

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑. 使用Android API,可以在Java环境开发App,编译.打包后可在Android系统 ...

  2. bootstrap-table 使用遇到的问题总结

    问题一:右上角button样式自定义 方法: //修改bootstrap-table右上角按钮样式 $(".table-box .columns-right button").re ...

  3. day 10 函数名的运用,闭包,迭代器

    函数名的本质 函数名本质上就是函数的内存地址 函数名的五种运用: 1.函数名是一个变量 def func(): print(666) print(func) # 函数的内存地址 <functio ...

  4. MD5加密和sha加密

    sha加密原理Algorithm)又叫安全哈希加密技术,是当今世界最先近的加密算法.主要用于文件身份识别.数字签名和口令加密等. 对于明文信息A,通过SHA1算法,生成一条160位长的识别码B.且明文 ...

  5. TabLayout+ViewPager的简单使用

    1.   build.gradle文件中加入 compile 'com.android.support:design:22.2.0' 2.写Xml文件,注意TabLayout的三个属性 app:tab ...

  6. go语言中的坑

    package main; import ( "fmt" "time" "sync" ) //修改slice的坑 func add(s [] ...

  7. c#devexpress GridContorl添加进度条

    demo 的实现图 下边是步骤和代码 1定义 时钟事件,定时的增加进度条的增量. 2:  添加进度条 3;定义字段属性 using System; using System.Collections.G ...

  8. sql建立一种,自定义的执行作业

    USE [chongwu] GO /****** Object: StoredProcedure [dbo].[p_createjob] Script Date: 01/21/2016 14:32:0 ...

  9. 引用类型中的push()、pop()、shift()方法

    /** * write by waitingbar1014 * time 2013.10.18 * 用途:常用于如一堆游戏激活码中获得抽取的值 * **/ //有以下一个数组: var arrayli ...

  10. spring boot (三): 热部署

    介绍了Spring boot实现热部署的两种方式,这两种方法分别是使用 Spring Loaded和使用spring-boot-devtools进行热部署. 热部署是什么 大家都知道在项目开发过程中, ...