【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 
#include 
#include 
#include 
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);
}

你可能感兴趣的:(【dp】New Keyboard)