P3736 [HAOI2016]字符合并

Posted edsheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3736 [HAOI2016]字符合并相关的知识,希望对你有一定的参考价值。

链接: https://www.luogu.org/recordnew/lists?uid=62242

题目描述

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

输入输出格式

输入格式:

 

第一行两个整数 n,kn,k 。

接下来一行长度为 nn 的 0101 串,表示初始串。输入的的相邻字符之间用一个空格隔开。

接下来 2^k2k 行,每行一个字符 c_ici? 和一个整数 w_iwi? , c_ici? 表示长度为 kk 的 0101 串连成二进制后按从小到大顺序得到的第 ii 种合并方案得到的新字符, w_iwi? 表示对应的第 ii 种方案对应获得的分数。

 

输出格式:

 

输出一个整数表示答案。

 

输入输出样例

输入样例#1: 复制
3 2
1 0 1
1 10
1 10
0 20
1 30
输出样例#1: 复制
40

说明

第3行到第6行表示长度为 22 的 44 种 0101 串合并方案。 0000 -> 11 ,得 1010 分, 0101 -> 11 得 1010 分, 1010 -> 00 得 2020分, 1111 -> 11 得 3030 分。

对于 100\%100% 的数据,

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

题解:

技术分享图片
#include<bits/stdc++.h>
using namespace std;
const int M = 305,     N = (1 << 8) + 1;
#define ll long long
int a[M], to[N];
ll w[N], dp[M][M][N], g[3];
const ll inf = -1e9;


int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++)scanf("%1d", &a[i]);
    for(int s = 0; s < (1 << k); s++)scanf("%d%lld", &to[s], &w[s]);
    memset(dp, 0x8f, sizeof(dp));
    for(int i = 1; i <= n; i++)dp[i][i][a[i]] = 0;
    
    for(int L = 2; L <= n; L++)
        for(int i = 1; i <= n - L + 1; i++){
            int j = i + L - 1, len = j - i;
            while(len > k - 1) len -= (k - 1);
            
            for(int mid = j; mid > 0; mid -= k-1){
                for(int s = 0; s < (1 << len); s++)
                if(dp[i][mid - 1][s] > inf){
                    if(dp[mid][j][1] > inf) 
                        dp[i][j][s<<1|1] = max(dp[i][j][s<<1|1], dp[i][mid - 1][s] + dp[mid][j][1]);
                    if(dp[mid][j][0] > inf) 
                        dp[i][j][s<<1] = max(dp[i][j][s<<1], dp[i][mid - 1][s] + dp[mid][j][0]);
                    //printf("%d %d %d %d %I64d %I64d
",len,i, j, s, dp[i][j][s<<1|1], dp[i][j][s<<1]);
                }    
            }
            if(len == k-1){
                    g[0] = g[1] = inf;
                    for(int s = 0; s < (1 << k); s++)
                        if(dp[i][j][s] > inf)
                            g[to[s]] = max(g[to[s]], dp[i][j][s] + w[s]);
                    dp[i][j][1] = g[1]; dp[i][j][0] = g[0];
                    //printf("%d %d %I64d %I64d    twice
",i, j, dp[i][j][0], dp[i][j][1]);
                }

        }
    
    ll ans = inf;
    for(int s = 0; s < (1 << k); s++)
        ans = max(ans, dp[1][n][s]);
    printf("%lld
", ans);
}
View Code

 

以上是关于P3736 [HAOI2016]字符合并的主要内容,如果未能解决你的问题,请参考以下文章

「HAOI2016」字符合并

BZOJ4565 [Haoi2016]字符合并

BZOJ4565HAOI2016字符合并 [状压DP][区间DP]

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

bzoj4566: [Haoi2016]找相同字符

玩具取名「HAOI2008」