【bzoj5147】casino 区间dp

题目描述

赌城拉斯维加斯的米高梅大赌场最近推出了一种新式赌法。它的玩法是由庄家设局(所用赌具是一批五颜六色的筹码),赌徒只要交付一定数额的赌资即可入局。开赌前庄家将手中的筹码依次排开铺成一排构成一局,然后公布若干个筹码序列供赌徒选择,赌徒可以从庄家设的局中取走与公布序列相一致的筹码,然后庄家将余下的筹码拼接好,赌徒再继续取筹码,直到赌徒没有筹码可取为止,此时赌徒用他取得的筹码到总台换取相应面值的现金。例如:庄家设的局为rrrgggbbb,r,g,b为筹码的颜色,庄家公布给赌徒选择的筹码序列为rg和gb,则赌徒可以取走第3和第4个筹码rg,庄家将余下的筹码拼接后组成rrggbbb;赌徒继续取走第3和第4个筹码rg,庄家将余下的筹码拼接后组成rgbbb;赌徒还是取走第3和第4个筹码rg,此时剩下的筹码为bbb,赌局结束;如果赌徒第二和第三次不取rg,而改取gb的话,终局时剩下的筹码为rrb。类似地终局时剩下的筹码也可以是rrr或rbb。已知每种颜色筹码的面值,给定庄家设的局和公布给赌徒选择的筹码序列,编程计算赌徒的最大收益。

输入

第一行为一个正整数 K (1 ≤ K ≤26),表示筹码的颜色种类,一种颜色对应一个小写英文字母。
接下来的K行每行有一个小写英文字母和一个正整数,二者之间用空格隔开,表示该小写英文字母代表的一个筹码的面额。 
第K+2行为一个长度不超过150的由小写英文字母组成的字符串,表示庄家设的局。
第K+3行为一个正整数N (1 ≤ N ≤ 150),表示公布给赌徒选择的筹码序列总数。
接下来的N行每行一个由小写英文字母组成的字符串,表示一个筹码序列,所有N个字符串的长度总和不超过150。

输出

输出文件仅有一行包含一个整数表示赌徒在这一局中可能获得的最大收益。

样例输入

6
a 1
b 4
d 2
x 3
f 1
e 3
fxeeabadd
2
aba
ed

样例输出

16


题解

区间dp

bzoj2121 ,只不过给出的是字符串总长限制,因此设状态时需要将所有串压成一个串,中间用空字符隔开。转移时直接dp新串的位置。

权值只需要在统计答案时加上。

具体见代码吧。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 155
using namespace std;
int a[26] , ans[N] , pos[N];
char str[N] , w[N] , tmp[3];
bool f[N][N] , g[N][N][N << 1];
int main()
{
	int t , n , m , x , len , l , r , i , j , sum = 0;
	scanf("%d" , &t);
	while(t -- ) scanf("%s%d" , tmp , &x) , a[tmp[0] - 'a'] = x;
	scanf("%s%d" , str + 1 , &m) , n = strlen(str + 1);
	for(i = 1 ; i <= n ; i ++ ) sum += a[str[i] - 'a'];
	pos[0] = -1;
	for(i = 1 ; i <= m ; i ++ )
		scanf("%s" , w + pos[i - 1] + 2) , pos[i] = strlen(w + pos[i - 1] + 2) + pos[i - 1] + 1;
	for(i = 1 ; i <= n ; i ++ )
	{
		f[i][i - 1] = 1;
		for(j = 0 ; j < m ; j ++ ) g[i][i - 1][pos[j] + 1] = 1;
	}
	for(len = 1 ; len <= n ; len ++ )
	{
		for(l = 1 ; l <= n - len + 1 ; l ++ )
		{
			r = l + len - 1;
			for(i = 0 ; i <= pos[m] ; i ++ )
			{
				if(str[r] == w[i]) g[l][r][i] |= g[l][r - 1][i - 1];
				for(j = l ; j <= r ; j ++ ) g[l][r][i] |= g[l][j - 1][i] & f[j][r];
			}
			for(i = 1 ; i <= m ; i ++ ) f[l][r] |= g[l][r][pos[i]];
		}
	}
	for(i = 1 ; i <= n ; i ++ )
	{
		ans[i] = ans[i - 1] + a[str[i] - 'a'];
		for(j = 1 ; j <= i ; j ++ )
			if(f[j][i])
				ans[i] = min(ans[i] , ans[j - 1]);
	}
	printf("%d\n" , sum - ans[n]);
	return 0;
}

 

 

posted @ 2018-03-06 21:00  GXZlegend  阅读(453)  评论(0编辑  收藏  举报