把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5202 [USACO19JAN]Redistricting P

题面传送门
吸了口氧一发最优解可还行。把\(G\)设为\(1\),把\(H\)设为\(-1\)\(sum\)为前缀和。
显然有\(O(nk)\)\(dp\):\(dp_i=\min\limits_{j=\max(1,i-k)}^{i-1}{dp_j+(sumi\geq sumj)}\)
这东西两个看起来不好优化。
但是注意后面那个只能是\(1/0\),所以只要\(dp_i<dp_j\)那么\(i\)的转移就一定不会比\(j\)的转移劣。
那么就可以按照\(dp_i\)单调队列了,注意\(dp_i\)相同要判\(sum_i\)的大小关系。
时间复杂度\(O(n)\)
代码实现:

#include<cstdio>
using namespace std;
int n,m,k,x,y,z,q[300039],head,tail,sum[300039],dp[300039];
char s;
inline bool cmp(int x,int y){return dp[x]==dp[y]?sum[x]<sum[y]:dp[x]>dp[y];}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;i++){
		s=getchar();
		while(s<'A'||s>'Z') s=getchar();
		sum[i]=sum[i-1]+(s=='G'?1:-1);
	}
	for(i=1;i<=n;i++){
		while(head<=tail&&q[head]+k<i) head++;
		j=q[head];dp[i]=dp[j]+(sum[i]-sum[j]>=0);//printf("%d ",dp[i]);
		while(head<=tail&&cmp(q[tail],i)) tail--;q[++tail]=i;
	}
	printf("%d\n",dp[n]);
}
posted @ 2021-01-22 21:33  275307894a  阅读(66)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end