HDU - 6549String (前缀优化dp)

it2023-09-27  86

wls 有一个长度为 nn 的字符串,每次他可以将一个长度不大于 ll 的子串修改成同一种字母,问至少修改多少次可以使字符串最多含有 kk 段。  连续的只含同 一种字母的子串被称为一段。比如说, aaabbccaaa共含有 4 段。

Input

第一行三个整数 n,l,k。  第二行一个字符串。  1 ≤ n ≤ 100, 000  1 ≤ l ≤ 100, 000  1 ≤ k ≤ 10

Output

一行一个数表示答案。

Sample Input

3 1 1 bab

Sample Output

1

定义状态  表示第 i 位前分了 j 段,操作后当前字符为 k 的最小操作次数

(1)

当前位不需要修改,直接从第 i - 1 位转移过来,分为两种情况, 和  

(2)

当前位需要修改,由于一次最多可以修改L个字符,所以要优先从i - L处转移,同样分为两种情况, 和 

可以发现当前的复杂度为,肯定会T,那么我们引入一个表示第 i 位(含)分了 j 段的最小修改次数,每次更新完 之后更新 即可。

引入后的转移方程:

(1)

(2)

​​​​​​​

前缀优化dp ?就这?

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 1e5 + 7; int dp[N][15][30], pre[N][15]; int main() { int n, p, l; string s; scanf("%d%d%d", &n, &l, &p); cin >> s; s = "#" + s; memset(dp, inf, sizeof(dp)); memset(pre, inf, sizeof(pre)); for(int i = 0; i < 26; ++i) { dp[0][0][i] = 0; dp[1][1][i] = 1; if(s[1] == i + 'a') dp[1][1][i] = 0; } pre[0][0] = 0; pre[1][1] = 0; for(int i = 2; i <= n; ++i) { for(int j = 1; j <= p; ++j) { for(int k = 0; k < 26; ++k) { if(s[i] == k + 'a') dp[i][j][k] = min({dp[i][j][k], dp[i - 1][j][k], pre[i - 1][j - 1]}); else { int id = max(0, i - l); dp[i][j][k] = min({dp[i][j][k], dp[id][j][k] + 1, pre[id][j - 1] + 1}); } pre[i][j] = min(pre[i][j], dp[i][j][k]); } } } int ans = inf; for(int i = 1; i <= p; ++i) for(int j = 0; j < 26; ++j) ans = min(ans, dp[n][i][j]); printf("%d\n", ans); return 0; }

 

最新回复(0)