字符合并

Time Limit: 20 Sec  Memory Limit: 256 MB
[Submit][Status][Discuss]

Description

  有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数。
  得到的新字符和分数由这 k 个字符确定。你需要求出你能获得的最大分数。

Input

  第一行两个整数n,k。接下来一行长度为n的01串,表示初始串。
  接下来2^k行,每行一个字符ci和一个整数wi,
  ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,
  wi表示对应的第i种方案对应获得的分数。

Output

  输出一个整数表示答案

Sample Input

  3 2
  101
  1 10
  1 10
  0 20
  1 30

Sample Output

  40

HINT

  1<=n<=300 ,0<=ci<=1, wi>=1, k<=8

Solution

  我们显然考虑区间DP,再状态压缩一下,f[l][r][opt]表示[l, r]合成了opt最大价值

  如果一个区间长度为len的话,最后合完会长度会变为len % (k - 1)

  转移的本质是把长度为k的区间变成0/1,分情况处理。

    先枚举每一个断点pos,表示我们要把[pos, r]合成一个0/1,那么就要保证(r - pos + 1) % (k - 1) = 1,否则我们DP的时候,会把000看做是0一样转移,导致不能合成为一个0/1的合成了。

    若len % (k -1) = 1,则合成完会剩下一个数,我们判断一下[l, r]能否合成一个opt的状态,若可以,则f[l][r][c[opt]] = max(f[l][r][opt] + val[opt])。注意要先拿一个变量记录下来,不能直接更新,否则会出现0状态更新了1,然后1又用0更新了的情况,导致答案过大。

  最后答案显然就是max(f[1][n][opt])

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long s64; const int ONE = ;
const int MOD = 1e9 + ; int n, k;
int total;
int a[ONE];
char s[ONE];
int c[ONE], val[ONE];
s64 f[ONE][ONE][ONE];
s64 Ans; int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} int main()
{
n = get(); k = get(); total = ( << k) - ; for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
for(int opt = ; opt <= total; opt++)
f[i][j][opt] = -; scanf("%s", s + );
for(int i = ; i <= n; i++)
a[i] = s[i] - '', f[i][i][a[i]] = ; for(int i = ; i <= total; i++)
c[i] = get(), val[i] = get(); for(int l = n; l >= ; l--)
for(int r = l; r <= n; r++)
{
if(l == r) continue; for(int pos = r - ; pos >= l; pos -= k - )
for(int opt = ; opt <= total; opt++)
{
if(f[l][pos][opt] == -) continue;
if(f[pos + ][r][] != - && (opt << ) <= total)
f[l][r][opt << ] = max(f[l][r][opt << ], f[l][pos][opt] + f[pos + ][r][]);
if(f[pos + ][r][] != - && (opt << | ) <= total)
f[l][r][opt << | ] = max(f[l][r][opt << | ], f[l][pos][opt] + f[pos + ][r][]);
} if((r - l + ) % (k - ) == || k == )
{
s64 A = -, B = -;
for(int opt = ; opt <= total; opt++)
if(f[l][r][opt] != -)
{
if(c[opt] == ) A = max(A, f[l][r][opt] + val[opt]);
if(c[opt] == ) B = max(B, f[l][r][opt] + val[opt]);
} f[l][r][] = max(f[l][r][], A);
f[l][r][] = max(f[l][r][], B);
}
} for(int opt = ; opt <= total; opt++)
Ans = max(Ans, f[][n][opt]); printf("%lld", Ans); }
  • 制作

【BZOJ4565】【HAOI2016】字符合并 [状压DP][区间DP]的更多相关文章

  1. BZOJ4565 [Haoi2016]字符合并

    题意 有一个长度为\(n\)的\(01\)串,你可以每次将相邻的\(k\)个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这\(k\)个字符确定.你需要求出你能获得的最大分数. \(n ...

  2. [BZOJ4565][HAOI2016]字符合并(区间状压DP)

    https://blog.csdn.net/xyz32768/article/details/81591955 首先区间DP和状压DP是比较明显的,设f[L][R][S]为将[L,R]这一段独立操作最 ...

  3. 2018.10.25 bzoj4565: [Haoi2016]字符合并(区间dp+状压)

    传送门 当看到那个k≤8k\le 8k≤8的时候就知道需要状压了. 状态定义:f[i][j][k]f[i][j][k]f[i][j][k]表示区间[i,j][i,j][i,j]处理完之后的状态为kkk ...

  4. BZOJ4565 HAOI2016字符合并(区间dp+状压dp)

    设f[i][j][k]为将i~j的字符最终合并成k的答案.转移时只考虑最后一个字符是由哪段后缀合成的.如果最后合成为一个字符特殊转移一下. 复杂度看起来是O(n32k),实际常数极小达到O(玄学). ...

  5. 【BZOJ】4565: [Haoi2016]字符合并

    4565: [Haoi2016]字符合并 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 690  Solved: 316[Submit][Status ...

  6. 洛谷 1063 dp 区间dp

    洛谷 1063 dp 区间dp 感觉做完这道提高组T1的题之后,受到了深深的碾压,,最近各种不在状态.. 初看这道题,不难发现它具有区间可并性,即(i, j)的最大值可以由(i, k) 与 (k+1, ...

  7. 【BZOJ 4565】 [Haoi2016]字符合并 区间dp+状压

    考试的时候由于总是搞这道题导致爆零~~~~~(神™倒序难度.....) 考试的时候想着想着想用状压,但是觉得不行又想用区间dp,然而正解是状压着搞区间,这充分说明了一件事,状压不是只是一种dp而是一种 ...

  8. 【BZOJ4565】 [Haoi2016]字符合并

    Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字 符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. I ...

  9. [Haoi2016]字符合并 题解

    tijie 时间限制: 2 Sec  内存限制: 256 MB 题目描述 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字 符和分数由这 ...

随机推荐

  1. kafka describe 显示结果解释

    > bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic Topic:my- ...

  2. 在MFC中显示cmd命令行

    添加函数 void InitConsoleWindow1() { ; FILE* fp; AllocConsole(); nCrt = _open_osfhandle((long)GetStdHand ...

  3. TP中if标签

    if标签 If标签如果php中if语句的作用,if是用于流程控制的. 在ThinkPHP中if标签也是用于流程控制的. If标签的语法格式: <if condition=’条件表达式’> ...

  4. webgl学习笔记四-动画

    写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放   下面我们将讲解下如何让一个正方形动起来~不断擦除和重绘 ...

  5. angularjs 常用功能练习

    <!DOCTYPE html> <html ng-app="app"> <head> <meta charset="utf-8& ...

  6. JavaScript 保留两位小数

    以下我们将为大家介绍 JavaScript 保留两位小数的实现方法: 四舍五入 以下处理结果会四舍五入: var num =2.446242342; num = num.toFixed(2); // ...

  7. 学习Python最好的方法就是实践和教程并行,以下有一些资源和教程,还有一些学习思维导图:

    1.Python 的 14 张思维导图下载地址: https://woaielf.github.io/2017/06/13/python3-all/ 2.Python基础教程|菜鸟教程: http:/ ...

  8. 【Java】判断字符串是否包含子字符串

    JAVA里面判断: public static void main(String[] args) { String str="ABC_001"; if(str.indexOf(&q ...

  9. Proving Equivalences UVALive - 4287(强连通分量 水题)

    就是统计入度为0 的点 和 出度为0 的点  输出 大的那一个,, 若图中只有一个强连通分量 则输出0即可 和https://www.cnblogs.com/WTSRUVF/p/9301096.htm ...

  10. QString::QString 中文乱码

    QString::QString 中文乱码 处理方法: 1. QString str = QString::fromLocal8Bit("中文"); // vs2008 vs200 ...