题意

给出一个长度为的01串 然后将相邻的个字符合并 得到一个新的字符并且获得一定的分数

解释一下样例 101 合并后面的01 得到一个1 然后分数是10 然后就变成11了 再合并11 就得到一个 1分数是30 所以总的分数就是40

为在范围状态为s的最大的值 在之间我们都以m为长度将每一个都合并 那么我们通过枚举,每次中间的分割点因为只能每个合成一个字母,所以每次就把分割点往前推个距离。并且合并之后的区间就会变成

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
const int N = 300 + 7;
const int INF = 0x3f3f3f3f;
ll w[1 << 8] , dp[N][N][1 <<8];
ll c[1 << 8];
char s[N];
ll  n , m;

void solve(){
    memset(dp , -0x3f , sizeof(dp));
    n = read() , m = read();
    scanf("%s" , s + 1);
    int sz = 1 << m ;
    for(int i = 0 ; i <= sz - 1 ; ++i){
        c[i] = read() , w[i] = read();
    }
    for(int i = 1 ; i <= n ; ++i){
        dp[i][i][s[i] - '0'] = 0;
    }
    for(int len = 2 ; len <= n ; ++len){
        for(int i = 1 , j = len ; j <=n ; ++i , ++j){
            int x = (len - 1 ) % (m - 1) + 1;
            if(x == 1){
                for(int k = 0 ; k < sz ; ++k){
                    for(int l = j - 1 ; l >= i ;l -= m - 1){
                        dp[i][j][c[k]] = max(dp[i][j][c[k]], dp[i][l][k >> 1] + dp[l + 1][j][k & 1] + w[k]);
                    }
                }
            }
            else{
                for(int k = 0 ; k < 1 << x ; ++k){
                    for(int l = j - 1 ; l >= i ; l -= m - 1)
                        dp[i][j][k] = max(dp[i][j][k] , dp[i][l][k >> 1] + dp[l + 1][j][k & 1]);
                }
            }
        }
    }
    ll ans = 0 ;
    for(int i = 0 ; i < sz - 1 ; ++i){
        ans = max(ans , dp[1][n][i]);
    }
    printf("%lld\n" , ans);
}

int main(void){
    solve();

    return 0;
}