[HAOI2016]字符合并 牛客
链接:https://ac.nowcoder.com/acm/problem/19997
来源:牛客网
题意:
有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数。得到的新字符和分数由这 k 个字符确定。你需要求出你能获得的最大分数。
设dp[i][j][s] ,表示从i到j字符串能到状态s的最大得分。
k个字符可以替换为1个字符,也就是字符串的长度减去4.
情况1:对于i~j的子串,当的长度能缩减为1个字符 即:(j-i)%(k-1)=0时,
dp[i][j][a[l]]=max(dp[i][j][a[l]],dp[i][m][l>>1]+dp[m+1][j][l&1]+b[l]);
每次取m(mid),也就是说前部分字符串dp[i][j][l>>1]缩减为状态a[l]的前k-1 位,dp[i][j][l&1] 替换为最后一位,然后这k位缩减位1位,即a[l]的值。l>>1 取前k-1位 l&1 取最后一位。
a[l]是二进制第i个长度为k的字符串被替换后的字符。(0或1)
b[i]是对应的得分。
情况2:对于i~j的子串,长度不能缩减为1个字符,则令t=(j-i)%(k-1)+1,t是缩减后的字符串长度。
dp[i][j][l]=max(dp[i][j][l],dp[i][m][l>>1]+dp[m+1][j][l&1];
最后取dp[1][n][i] 的最大值就是结果。
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
#include<queue>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<math.h>
#include<stdlib.h>
#include<stack>
#include<stdio.h>
#include<vector>
#include<set>
#include<bitset>
#include<map>
#include<string.h>
#include<complex>
#define ll long long
#define ull unsigned long long
#define db double
#define scan(n) scanf("%d",&n)
using namespace std;
int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int mx=1e6+10,inf=1e9+10,mod=1000000007;
int n,k;
int c[500],a[1000],b[1000];
ll dp[350][350][500];
string s;
int main(){
#ifdef LOCAL_flyTY
freopen("in.txt","r",stdin);
#endif
cin>>n>>k;
cin>>s;
int len=1<<k;
for(int i=0;i<len;i++){
scan(a[i]);
scan(b[i]);
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
for(int k=0;k<=len;k++){
dp[i][j][k]=-1e9;
}
}
}
for(int i=1;i<=n;i++){
c[i]=s[i-1]-'0';
dp[i][i][c[i]]=0;
}
for(int x=2;x<=n;x++){
for(int i=1,j=x;j<=n;i++,j++){
int t=(x-1)%(k-1)+1;
if(t==1){
for(int l=0;l<len;l++){
for(int m=j-1;m>=i;m-=(k-1)){
dp[i][j][a[l]]=max(dp[i][j][a[l]],dp[i][m][l>>1]+dp[m+1][j][l&1]+b[l]*1ll);
}
}
}else{
t=1<<t;
for(int l=0;l<t;l++){
for(int m=j-1;m>=i;m-=(k-1)){
dp[i][j][l]=max(dp[i][j][l],dp[i][m][l>>1]+dp[m+1][j][l&1]);
}
}
}
}
}
ll ans=0;
for(int i=0;i<len;i++){
ans=max(ans,dp[1][n][i]);
}
cout<<ans<<endl;
return 0;
}