"The combined range of characters like pressure dp dp"

<> Yes

<First update>


<Text>

Character merger

Description

There is a 01 string of length n, you can each adjacent k characters were combined to give a new character and get a certain score. Get new characters and scores are determined by the k characters. You need to find the maximum score you can get.

Input Format

The first line of two integers n, k. The next line of the 01 strings of length n, represents the initial string.

Next, 2 ^ k lines of a character and an integer Wi ci, ci denotes the length of the new i-th character by combining scheme in ascending order of k obtained after the 01 binary series obtained, wi represents the corresponding corresponding to the i th fraction obtained embodiment.

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

Output Format

Output represents an integer answer

Sample Input

3 2
101
1 10
1 10
0 20
1 30

Sample Output

40

Resolve

First of all, it is easy to think of the interval \ (dp \) : \ (f [L] [r] \) represents the merger interval \ ([l, r] \ ) of the maximum score. But this record status does not seem good, because some of the characters will leave the interval after the merger, these characters will have some value.

If we consider the merger can merge, we found that the remaining number of characters in a range of no more than \ (k \) a, \ (k \ Leq 8 \) .

那就考虑状态压缩:\(f[l][r][S]\)代表合并区间\([l,r]\),得到字符集\(S\)的最大价值。然后我们就考虑用区间\(dp\)的框架来执行转移。首先,我们一定要枚举一个断点,然后合并两个区间。但是现在我们状态中还有一个\(S\),难道再枚举两个\(S_1,S_2\)来合并吗?

这样时间复杂度肯定是承受不了的。有一种更好的转移方式就是每次只考虑断点右边的区间合并成原区间状态\(S\)中的最后一个字符,这样同样可以做到更新不存在遗漏。

那么我们根据这样的方式转移即可:\(1.\) 执行通过子区间合并的转移。 \(2.\) 当区间长度可以合并时,执行计算合并贡献的转移。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 302 , K = 8;
const long long INF = 0x3f3f3f3f;
int n,k,a[N],c[1<<K];
long long w[1<<K],f[N][N][1<<K];
inline void input(void)
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        scanf("%1d",&a[i]);
    for (int i=0;i<1<<k;i++)
        scanf("%d%lld",&c[i],&w[i]);
}
inline void DynamicProgram(void)
{
    memset( f , 0xcf , sizeof f );
    for (int i=1;i<=n;i++) f[i][i][a[i]] = 0;
    for (int len=2;len<=n;len++)
        for (int l=1,r;(r=l+len-1)<=n;l++)
        {
            int L = (len-1) % (k-1);
            if ( L == 0 ) L = k-1;
            for (int mid=r-1;mid>=l;mid-=k-1)
                for (int S=0;S<1<<L;S++)
                    f[l][r][S<<1] = max( f[l][r][S<<1] , f[l][mid][S] + f[mid+1][r][0] ),
                    f[l][r][S<<1|1] = max( f[l][r][S<<1|1] , f[l][mid][S] + f[mid+1][r][1] );
            if ( L == k-1 )
            {
                long long g[2] = {-INF,-INF};
                for (int S=0;S<1<<k;S++)
                    g[c[S]] = max( g[c[S]] , f[l][r][S] + w[S] );
                f[l][r][0] = g[0] , f[l][r][1] = g[1];
            }
        }
}
int main(void)
{
    input();
    DynamicProgram();
    long long ans = -INF;
    for (int S=0;S<1<<k;S++)
        ans = max( ans , f[1][n][S] );
    printf("%lld\n",ans);
    return 0;
}

<后记>

Guess you like

Origin www.cnblogs.com/Parsnip/p/11520358.html