「HAOI2016」字符合并

题目描述

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

数据范围

$1 \leq n \leq 300, \ 0 \leq c_i \leq 1, \ w_i \geq 1, \ k \leq 8$

题解

数据范围较小,考虑区间 $dp$ , $f_{l,r,s}$ 表示 $[l,r]$ 最后合并成状态 $s$ 的最大分数,可以通过 $l,r$ 知道 $s$ 的长度

考虑转移,发现只要枚举中间点 $x$ ,让 $[l,x]$ 合成前 $s-1$ 位, $(x,r]$ 合成最后一位即可

注意当 $s$ 的长度为 $0$ 时,将其变为 $k$ 即可

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=305;
int n,k,a[N],b[N],c[N];
LL f[N][N][N],ans=-2e18;
char s[N];
int main(){
    scanf("%d%d%s",&n,&k,s+1);
    for (int i=1;i<=n;i++) c[i]=s[i]^48;
    for (int i=0;i<(1<<k);i++)
        scanf("%d%d",&a[i],&b[i]);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            for (int l=0;l<(1<<k);l++)
                f[i][j][l]=-2e18;
    for (int i=1;i<=n;i++) f[i][i][c[i]]=0;
    for (int len=1;len<n;len++){
        for (int r,v,l=1;l+len<=n;l++){
            r=l+len;v=(r-l)%(k-1)+1;
            if (v==1){
                for (int w=0;w<(1<<k);w++)
                    for (int x=r-1;x>=l;x-=k-1)
                        f[l][r][a[w]]=max(f[l][r][a[w]],f[l][x][w>>1]+f[x+1][r][w&1]+b[w]);
            }
            else{
                for (int w=0;w<(1<<v);w++)
                    for (int x=r-1;x>=l;x-=k-1)
                        f[l][r][w]=max(f[l][r][w],f[l][x][w>>1]+f[x+1][r][w&1]);
            }
        }
    }
    for (int i=0;i<(1<<k);i++)
        ans=max(ans,f[1][n][i]);
    return printf("%lld\n",ans),0;
}

原文地址:https://www.cnblogs.com/xjqxjq/p/11779208.html

时间: 2024-08-12 06:21:53

「HAOI2016」字符合并的相关文章

LibreOJ #2061. 「HAOI2016」放棋子

二次连通门 : LibreOJ #2061. 「HAOI2016」放棋子 /* LibreOJ #2061. 「HAOI2016」放棋子 MDZZ ... 错排 + 高精 */ #include <iostream> #include <cstdio> #include <vector> #include <iomanip> #include <cassert> #include <algorithm> #define int64 l

bzoj4565【HAOI2016】字符合并

4565: [Haoi2016]字符合并 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 102  Solved: 49 [Submit][Status][Discuss] Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字 符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. Input 第一行两个整数n,k.接下来一行长度为n的01串,表示初始串.接下

2017.8.15 [Haoi2016]字符合并 区间dp+状压dp

[题目描述] 有一个长度为n的01串,你可以每次将相邻的k个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这k个字符确定.你需要求出你能获得的最大分数. [输入格式] 第一行两个整数n,k. 接下来一行长度为n的01串,表示初始串.输入的的相邻字符之间用一个空格隔开. 接下来2k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符, wi表示对应的第i种方案对应获得的分数. [输出格式] 输出一个整数表示答案. [

【BZOJ4565】 [Haoi2016]字符合并

Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字 符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. Input 第一行两个整数n,k.接下来一行长度为n的01串,表示初始串.接下来2k行,每行一个字符ci和一个整数wi,ci 表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,wi表示对应的第i种方案对应 获得的分数.1<=n<=300,0<=ci<=1,w

P3736 [HAOI2016]字符合并

链接: https://www.luogu.org/recordnew/lists?uid=62242 题目描述 有一个长度为 nn 的 0101 串,你可以每次将相邻的 kk 个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这 kk 个字符确定.你需要求出你能获得的最大分数. 输入输出格式 输入格式: 第一行两个整数 n,kn,k . 接下来一行长度为 nn 的 0101 串,表示初始串.输入的的相邻字符之间用一个空格隔开. 接下来 2^k2k 行,每行一个字符 c_ici? 

「SCOI2016」萌萌哒

「SCOI2016」萌萌哒 题目描述 一个长度为 \(n\) 的大数,用 \(S_1S_2S_3 \ldots S_n\) 表示,其中 \(S_i\) 表示数的第 \(i\) 位,\(S_1\) 是数的最高位,告诉你一些限制条件,每个条件表示为四个数 $(l_1, r_1, l_2, r_2) $,即两个长度相同的区间,表示子串 $S_{l_1}S_{l_1 + 1}S_{l_1 + 2} \ldots S_{r_1} $与 \(S_{l_2}S_{l_2 + 1}S_{l_2 + 2} \ld

JavaScript 引擎「V8」发布 8.0 版本,内存占用量大幅下降

上周,JavaScript 引擎「V8」的开发团队在该项目官方网站上正式宣布推出最新的 8.0 版本.这次更新的重点主要集中在错误修复及性能改善上,正式的版本将在数周后随着谷歌 Chrome 80 稳定版一起发布. V8 是谷歌公司推出的开源高性能 JavaScript 引擎,主要用于提升 Web 浏览器内部 JavaScript 脚本执行的性能.V8 通过 C++ 语言编写,主要用在 Chrome 浏览器以及 Node.js 上,实现了对 ECMAScript 与 WebAssembly 的支

程序员「奇葩」说

一直以来「奇葩」这个词都是偏贬义的,直到去年有个综艺节目叫「奇葩说」挺热闹,这里的人不一定是奇葩,更多指达人的意思. 「奇葩说」里的达人都是能说会道的,我的主业是程序员,所以只能写写在我职业生涯中碰到的一些「奇葩」程序员. 你懂的,我这里的「奇葩」没有任何贬义的意思. 月在胸襟人在途 我刚入行时的第一位项目经理,70后.那年三十出头,在银行客户现场做项目经理,负责一个二十来人的客户现场团队. 虽然他的职位是项目经理,但实际那时他真是一名地道的资深程序员. 70 后的程序员大都是从写 C 开始的,

LibreOJ #2013. 「SCOI2016」幸运数字

二次联通门 : LibreOJ #2013. 「SCOI2016」幸运数字 /* LibreOJ #2013. 「SCOI2016」幸运数字 树链剖分 + 线段树 + 线性基合并 没什么可说的 对原树进行树链剖分 然后建线段树 每个区间维护一段线性基 每次暴力把一段插入另一段中 最后线性基求最大即可 注意线性基求最大时一定是倒着枚举的 */ #include <cstdio> #include <iostream> const int BUF = 12312334; char Bu