【Luogu_P5839】 [USACO19DEC] Moortal Cowmbat G【动态规划】
P5839 [USACO19DEC] Moortal Cowmbat G
题目描述
Bessie 玩格斗游戏真牛快打已经有很长时间了。然而,最近游戏开发者发布了一项更新,这迫使 Bessie 改变她的打法。
游戏总共使用 MMM 个按键,标记为前 MMM 个小写字母。Bessie 在游戏中最喜欢的组合键是一个长为 NNN 的按键字符串 SSS。然而,由于最近的更新,现在每种组合键必须由一些“连击”所组成,其中连击的定义为相同的按键连续按下至少 KKK 次。Bessie想要修改她最喜欢的组合键,创造一个同样长为 NNN 的新组合键,然而这一新组合键由按键连击所组成,以适应规则的变化。
Bessie 需要消耗 aija_{ij}aij 天来训练她在组合键中某个特定的位置用按键 jjj 来取代按键 iii(也就是说,将 SSS 中的某个特定的字符由 iii 变为 jjj 的代价为 aija_{ij}aij)。注意有可能将按键 iii 换成某种中间按键 kkk 然后再从按键 kkk 换成按键 jjj 会比直接从按键 iii 换成按键 jjj 消耗更短的时间(或者更一般地说,可能有一条起点为 iii 终点为 jjj 的更改路径给出了从按键 iii 最终更改为按键 jjj 的最小总代价)。
帮助 Bessie 求出她创建一个满足新要求的组合键所需要的最小天数。
输入格式
输入的第一行包含 NNN,MMM 和 KKK。第二行包含 SSS,最后 MMM 行包含一个 M×MM\times MM×M 的数字方阵 aija_{ij}aij,其中 aija_{ij}aij 为一个范围为 0…10000 \ldots 10000…1000 的整数,并且对于所有的 iii,有 aii=0a_{ii} = 0aii=0。
输出格式
输出一个整数,表示 Bessie 将她的组合键改为一个满足新要求的新的组合键所需要的最小天数。
输入输出样例 #1
输入 #1
5 5 2
abcde
0 1 4 4 4
2 0 4 4 4
6 5 0 3 2
5 5 5 0 4
3 7 0 5 0
输出 #1
5
说明/提示
在这个例子中的最优方案是将 a
改为 b
,将 d
改为 e
,再将两个 e
都改为 c
。这总共消耗 1+4+0+0=51+4+0+0=51+4+0+0=5 天,最终的组合键为 bbccc
。
测试点性质:
测试点 2∼42\sim 42∼4 满足 N≤1000N\le 1000N≤1000,K≤50K\le 50K≤50。
测试点 5∼85\sim 85∼8 满足 N≤3×104N\le 3\times 10^4N≤3×104,K≤50K\le 50K≤50。
对于 100%100\%100% 的数据,1≤M≤261 \leq M \leq 261≤M≤26,1≤K≤N≤1051 \leq K\leq N \leq 10^51≤K≤N≤105。
供题:Eric Wei
思路:
先跑floyd
可以考虑DP,设fi,jf_{i,j}fi,j为到第iii位,第iii位为jjj的最短时间。
然后可以发现第二维可以不用管。
因为要保证连续kkk个相同的键,所以在DP到iii时,将i−ki - ki−k加入维护数组。
每次维护数组的更新就是在,自身+当前位变为jjj的代价,和,fi−k+cost(i−k+1f_{i - k}+cost(i - k + 1fi−k+cost(i−k+1 ~ i)~i) i),之间的最小。
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>#define ll long longusing namespace std;const ll MAXN = 1e5 + 5;ll n, m, K;
char s[MAXN];
ll a[30][30];
ll f[MAXN], ls[MAXN][30], q[MAXN];int main() {scanf("%lld%lld%lld", &n, &m, &K);scanf("%s", s + 1);for(ll i = 1; i <= m; i ++)for(ll j = 1; j <= m; j ++) scanf("%lld", &a[i][j]);for(ll k = 1; k <= m; k ++)for(ll i = 1; i <= m; i ++)for(ll j = 1; j <= m; j ++)if(i != j && j != k && k != i) if(a[i][j] > a[i][k] + a[k][j]) a[i][j] = a[i][k] + a[k][j];for(ll i = 1; i <= m; i ++)for(ll j = 1; j <= n; j ++)ls[j][i] = ls[j - 1][i] + a[s[j] - 'a' + 1][i];memset(f, 1, sizeof(f));memset(q, 1, sizeof(q));f[0] = 0;for(int i = K; i <= n; i ++)for(int j = 1; j <= m; j ++) {q[j] = min(q[j] + a[s[i] - 'a' + 1][j], f[i - K] + ls[i][j] - ls[i - K][j]);f[i] = min(f[i], q[j]);}printf("%lld", f[n]);return 0;
}