[Codeforces Gym - 101617A] Ducks in a Row

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/82385021

题目链接

https://vjudge.net/contest/248767#problem/A

题目大意

给你一个只含字符’D’和’G’的字符串S ( 1 | S | 2000 ) , 每次可以选择一个子区间翻转(‘D’变成’G’, ‘G’变成’D’),费用为1。 求最少费用, 使得存在至少n个长度至少为k的极大’D’子串 ( 1 n , k 2000 )

题目思路

很容易想到dp, f[i][j][k][rev], 表示考虑前i个字符, 当前满足条件的有j段, 后缀’D’的长度为k, 第i个点翻转状态为rev, 进行转移即可。 这个dp乍一看像是O(n^3)的, 实际上当|S|

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <bitset>
#include <map>
#include <stack>
#include <set>

#define ls ch[x][0]
#define rs ch[x][1]
#define ll long long
#define pi pair<int, int>
#define mp make_pair
#define fi first
#define se second

using namespace std;
int gi(){
    int ret = 0; char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)){
        ret = ret * 10 + c - '0';
        c = getchar();
    }
    return ret;
}

const int N = (int)2020 + 10;
const int M = (int)2e7 + 10;

int m, k, n; char s[N];
int f[M];

int id(int i, int j, int h, int rev){
    return rev + h * 2 + j * (m + 1) * 2 + i * (k + 1) * (m + 1) * 2;
}
void update(int &x, int y){
    if (y == -1) return;
    if (x == -1) x = y;
    else x = min(x, y);
}

int main(){

    scanf("%d %d", &m, &k);
    scanf("%s", s + 1); n = strlen(s + 1);

    if (n < m * k){puts("-1"); return 0;}

    f[id(0, 0, 0, 0)] = 0;
    for (int i = 1; i < M; i ++) f[i] = -1;

    for (int i = 0; i < n; i ++)
        for (int j = 0; j <= k; j ++)
            for (int h = 0; h <= m; h ++)
                for (int rev0 = 0; rev0 <= 1; rev0 ++)
                    for (int rev1 = 0; rev1 <= 1; rev1 ++){
                        int dw = rev1 && !rev0;
                        int dh = s[i + 1] == (rev1 ? 'G' : 'D') ? min(h + 1, m) : 0;
                        int dj = h == m - 1 && dh == m;
                        int v = id(i + 1, min(j + dj, k), dh, rev1);
                        int u = id(i, j, h, rev0);
                        if (f[u] == -1) continue;
                        update(f[v], f[u] + dw);
                    }

    int ans = -1;
    for (int h = 0; h <= m; h ++)
        for (int rev = 0; rev <= 1; rev ++)
        update(ans, f[id(n, k, h, rev)]);

    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/82385021