【bzoj5147】casino 區間dp

題目描述html

賭城拉斯維加斯的米高梅大賭場最近推出了一種新式賭法。它的玩法是由莊家設局(所用賭具是一批五光十色的籌碼),賭徒只要交付必定數額的賭資便可入局。開賭前莊家將手中的籌碼依次排開鋪成一排構成一局,而後公佈若干個籌碼序列供賭徒選擇,賭徒能夠從莊家設的局中取走與公佈序列相一致的籌碼,而後莊家將餘下的籌碼拼接好,賭徒再繼續取籌碼,直到賭徒沒有籌碼可取爲止,此時賭徒用他取得的籌碼到總檯換取相應面值的現金。例如:莊家設的局爲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。

輸出spa

輸出文件僅有一行包含一個整數表示賭徒在這一局中可能得到的最大收益。

樣例輸入code

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

樣例輸出blog

16字符串


題解get

區間dpstring

bzoj2121 ,只不過給出的是字符串總長限制,所以設狀態時須要將全部串壓成一個串,中間用空字符隔開。轉移時直接dp新串的位置。it

權值只須要在統計答案時加上。

具體見代碼吧。

#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;
}
相關文章
相關標籤/搜索