Invoker(预处理+dp)

Invoker

[Link](Problem - 6739 (hdu.edu.cn))

题意

你有三个小技能,每使用一个小技能就会给你的卡槽留下一个相应的标记,卡槽最多有三个标记,当有一个新的标记到来且没有位置时最先到的标记被移除,依次顺移。卡槽内三个标记不同的无序组合可以放出不同的大招,当有三个标记后就可以放大招啦。现在给你一个大招序列,问你最少用多少次操作可以把这个大招序列发出去。

题解

首先发现每一个大招就确定了三个无序的标记,它是不符合局部贪心到整体最优的。但是假设当前到了第i位,那么从开始到第i位的所有操作,是有一个最优解的且和后面的操作无关。因此想到的dp,那么怎么考虑设计维度可以补充不漏的把状态表示出来呢?首先假设当前到了第i位,那么第i-1位时什么情况下他是最优的呢,这个是无法直接判断了因此我们要加一维来表示前一个大招的标记情况。我们假设
f [ i , j ] 表 示 到 第 i 个 大 招 且 是 第 j 种 标 记 情 况 的 最 小 操 作 次 数 f[i,j]表示到第i个大招且是第j种标记情况的最小操作次数 f[i,j]ij
然后就可以直接暴力转移了。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
char dic[10][6][4] {
    {"QQQ","QQQ","QQQ","QQQ","QQQ","QQQ"},
    {"QQW","QWQ","WQQ","QQW","QWQ","WQQ"},
    {"QQE","QEQ","EQQ","QQE","QEQ","EQQ"},
    {"WWW","WWW","WWW","WWW","WWW","WWW"},
    {"QWW","WQW","WWQ","QWW","WQW","WWQ"},
    {"WWE","WEW","EWW","WWE","WEW","EWW"},
    {"EEE","EEE","EEE","EEE","EEE","EEE"},
    {"QEE","EQE","EEQ","QEE","EQE","EEQ"},
    {"WEE","EWE","EEW","WEE","EWE","EEW"},
    {"QWE","QEW","WQE","WEQ","EWQ","EQW"},
};
map<char, int> mp;
int s[N];
string str;
int f[N][6];
int get(int v1, int v2, int p1, int p2) {
    if (dic[v1][p1][0] == dic[v2][p2][0] && dic[v1][p1][1] == dic[v2][p2][1] && dic[v1][p1][2] == dic[v2][p2][2])   return 0;
    if (dic[v1][p1][1] == dic[v2][p2][0] && dic[v1][p1][2] == dic[v2][p2][1]) return 1;
    if (dic[v1][p1][2] == dic[v2][p2][0])   return 2;
    return 3;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    mp['Y'] = 0,mp['V'] = 1,mp['G'] = 2,mp['C'] = 3,mp['X'] = 4,
    mp['Z'] = 5,mp['T'] = 6,mp['F'] = 7,mp['D'] = 8,mp['B'] = 9;
    while(cin >> str) {
        int res = 0, cnt = 0;
        for (int i = 0; i < str.size(); i ++ ) s[i + 1] = mp[str[i]];
        memset(f, 0x3f, sizeof f);
        for (int i = 0; i < 6; i ++ ) f[1][i] = 3;
        for (int i = 2; i <= str.size(); i ++ )
            for (int j = 0; j < 6; j ++ )
                for (int k = 0; k < 6; k ++ )   
                    f[i][j] = min(f[i][j], f[i - 1][k] + get(s[i-1], s[i], k, j));
        int mn = INF;
        for (int i = 0; i < 6; i ++ )   mn = min(mn, f[str.size()][i]);
        cout << mn + str.size()  << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值