Usaco 2019 Jan Platinum
要不是昨天老师给我们考了这套题,我都不知道usaco还有铂金这么一级。
插播一则新闻:杨神坚持认为铂金比黄金简单,原因竟是:铜 汞 银 铂 金(金属活动性顺序表)
Usaco真是慢的不行,所以就贴洛谷链接啦。
Redistricting: https://www.luogu.org/problemnew/show/P5202
题意概述:给出一个长度为N的序列,由'H'和'G'组成,将它分为任意段,每段的长度不超过 $K$ ,要求最小化(H比较少的段)的数量。$k<=n<=3 \times 10^5$
首先可以将原序列中的G视为一,做一遍前缀和,那么就有了一个 $O(NK)$ 的朴素dp:
# include <cstdio> # include <iostream> # include <cstring> # define nl (n<<1) # define nr (n<<1|1) # define R register int using namespace std; const int maxn=300005; const int inf=100000000; int n,k,a[maxn],f[maxn],g[maxn],q[maxn],H=1,T; char s[maxn]; void add (int x) { while(H<=T&&((f[x]<f[ q[T] ])||(f[x]==f[ q[T] ]&&g[x]<=g[ q[T] ]))) T--; q[++T]=x; } void del (int x) { while (H<=T&&q[H]<=x) H++; } int ask (int x) { if(g[ q[H] ]<g[x]) return f[ q[H] ]; return f[ q[H] ]+1; } int main() { scanf("%d%d",&n,&k); scanf("%s",s+1); for (R i=1;i<=n;++i) { if(s[i]=='G') a[i]=a[i-1]+1; else a[i]=a[i-1]; g[i]=i-2*a[i]; } f[0]=0; for (R i=1;i<=n;++i) { add(i-1); if(i-k-1>=0) del(i-k-1); f[i]=ask(i); } printf("%d",f[n]); return 0; }