【dp】New Keyboard

http://codeforces.com/gym/101397
B

dp[i][j][k]: i为前一个行动的状态,0-switch、1-type,j为当前状态layout的编号,k 是已键入的字符数量。
遍历k,对每个k遍历j: 1..n

dp[0][j % n + 1][k] = min(dp[0][j % n + 1][k], min(dp[0][j][k] + b, dp[1][j][k] + a))

↑ 执行两次,第二遍处理是为了保证n->1之后正确

dp[1][j][k + 1] = min(dp[0][j][k], dp[1][j][k]) + c

最后答案取min(dp[1][1..n][len])

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2005;
char str[maxn];
bool mark[maxn][26];
int n, a, b, c, len;
ll dp[2][maxn][maxn];
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main() {
	memset(dp, 0x3f, sizeof dp);
	scanf("%d%d%d%d", &n, &a, &b, &c);
	for (int j = 1; j <= n; j++) {
		char s[maxn];
		scanf("%s", s);
		int lens = strlen(s);
		for (int k = 0; k < lens; k++) {
			mark[j][s[k] - 'a'] = true;
		}
	}
	scanf("%s", str);
	len = strlen(str);
	dp[1][1][0] = 0;
	for (int k = 0; k <= len; k++) {
		for (int j = 1; j <= n; j++) {
			dp[0][j % n + 1][k] = min(dp[0][j % n + 1][k], min(dp[0][j][k] + b, dp[1][j][k] + a));
		}
		for (int j = 1; j <= n; j++) {
			dp[0][j % n + 1][k] = min(dp[0][j % n + 1][k], min(dp[0][j][k] + b, dp[1][j][k] + a));
		}
		for (int j = 1; j <= n; j++) {
			if (mark[j][str[k] - 'a']) {
				dp[1][j][k + 1] = min(dp[1][j][k], dp[0][j][k]) + c;
			}
		}
	}
	ll ans = dp[1][1][len];
	for (int j = 2; j <= n; j++) {
		ans = min(ans, dp[1][j][len]);
	}
	printf("%I64d\n", ans == INF ? -1 : ans);
}
posted @ 2018-09-06 01:39  Stolf  阅读(245)  评论(0编辑  收藏  举报