[USACO19JAN]Redistricting——单调队列优化DP

原题链接
首先有一个\(O(nk)\)的很显然的\(dp\),把荷斯坦牛看成\(1\),把更赛牛看成\(-1\),这样就可以很方便地通过前缀和来判断某一段中谁有优势了
考虑怎么优化,观察转移:
\[f[i]=min\{f[j]+[sum[i]-sum[j]\leqslant 0]\},1\leqslant i-j\leqslant k\]
因为\([sum[i]-sum[j]\leqslant 0]\)只能为\(0\)\(1\),那么我们开一个双关键字的单调队列维护一下就好了
代码在此:

#include <algorithm>
#include  <iostream>
#include   <cstdlib>
#include   <cstring>
#include    <cstdio>
#include    <random>
#include    <string>
#include    <vector>
#include     <cmath>
#include     <ctime>
#include     <queue>
#include       <map>
#include       <set>

#define IINF 0x3f3f3f3f3f3f3f3fLL
#define u64 unsigned long long
#define pii pair<int, int>
#define mii map<int, int>
#define u32 unsigned int
#define lbd lower_bound
#define ubd upper_bound
#define INF 0x3f3f3f3f
#define vi vector<int>
#define ll long long
#define mp make_pair
#define pb push_back
#define is insert
#define se second
#define fi first
#define ps push

#define $SHOW(x) cout << #x" = " << x << endl
#define $DEBUG() printf("%d %s\n", __LINE__, __FUNCTION__)

using namespace std;

#define MAXN 300000

struct Data {
    int id, dp, sum;
    bool operator < (const Data &rhs) {
        return dp == rhs.dp ? sum < rhs.sum : dp < rhs.dp;
    }
}q[MAXN + 5];

int n, k, sum[MAXN + 5], f[MAXN + 5], head, tail;
char s[MAXN + 5];

int main() {
    scanf("%d%d%s", &n, &k, s + 1);
    for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + (s[i] == 'H' ? 1 : -1);
    q[tail++] = Data{0, 0, 0};
    for (int i = 1; i <= n; ++i) {
        while (head < tail && q[head].id < i - k) head++;
        Data cur{i, f[i] = q[head].dp + (sum[i] - q[head].sum <= 0), sum[i]};
        while (head < tail && cur < q[tail - 1]) tail--;
        q[tail++] = cur;
    }
    printf("%d\n", f[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/dummyummy/p/11042022.html
今日推荐