题解 P5202 【[USACO19JAN]Redistricting】
这里用单调队列实现,吊打堆,时间复杂度只需O(n)
首先看到此题想到DP。容易得出下面的式子:
记
由于枚举j肯定要超时,我们想到用数据结构来维护DP
如果没有
对于
若
若
有了以上推论&细节&卡常,你就不仅能AC,RP好还能进入最优解第一面(女装有益减小常数QwQ)
以下是代码(131ms)
#pragma GCC optimize ("Ofast")
#include <cstdio>
using namespace std;
inline void read (int& s) {
s = 0;
static char c = getchar ();
while (c < '0' || c > '9') c = getchar ();
while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c & 15), c = getchar ();
return ;
}
const int N = 300007;
int n, k, f[N], sum[N];
int Q[N], H, T;
int main () {
read (n), read (k);
register int i; for (i = 1; i <= n; ++i) sum[i] = sum[i - 1] + (getchar () == 'H' ? 1 : -1);
Q[T++] = 0; //刚开始前0头牛答案为0
for (i = 1; i <= n; ++i) {
while (H < T && i - Q[H] > k) ++H; //单调队列的出队操作
f[i] = f[Q[H]] + (sum[i] - sum[Q[H]] <= 0);
while (H < T) {
if (f[i] < f[Q[T - 1]] || (f[i] == f[Q[T - 1]] && sum[i] < sum[Q[T - 1]])) --T;
else break;
} //入队操作,注意一下细节
Q[T++] = i;
}
printf ("%d\n", f[n]);
return 0;
}
个人觉得单调队列好写,好记,好快,为什么还用堆来维护呢