P5202 [USACO19JAN] Redistricting P

洛谷

首先我们设更赛牛为加一,荷斯坦牛为负一。

这样通过前缀和就可以得到这一组是否需要增加一。

\(dp_i\) 表示以 \(i\) 为末尾,最少的分区。

那么方程式就为:

\[dp_i=dp_j+(pre_i-pre_j\le 0) \]

然而表达式我们并不好判断。

但是由于表达式只能提供数值为一的贡献,那么我们可以使用优先队列,以 \(dp_j\) 的值排序,在 \(dp_j\) 相同时按照 \(pre_j\) 排序,取出最小值即可。

由于选择的区域有限,第一种处理方式是在结构体内记录下位置,若取出的值不合法则删除后再取一次。

对于第二种方法,可以直接使用带删的优先队列。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,dp[300005],pre[300005];
char a[300005];
struct P{
	int x,y;
	bool friend operator<(P a,P b){
		if(a.x!=b.x)return a.x>b.x;
		return a.y>b.y;
	}
};
struct Q{
	priority_queue<P> q1,q2;
	void push(P x){
		q1.push(x);
	}
	void pop(P x){
		q2.push(x);
	}
	P top(){
		while(!q1.empty()&&!q2.empty()&&q1.top().x==q2.top().x&&q1.top().y==q2.top().y){
			q1.pop();
			q2.pop();
		}
		return q1.top();
	}
}q;
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		if(a[i]=='G')pre[i]=-1;
		else pre[i]=1;
	}
	for(int i=1;i<=n;i++)pre[i]+=pre[i-1];
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	q.push({0,0});
	for(int i=1;i<=n;i++){
		if(i-k-1>=0)q.pop({dp[i-k-1],pre[i-k-1]});
		P u=q.top();
		dp[i]=u.x+(pre[i]-u.y<=0);
		q.push({dp[i],pre[i]});
	}
	cout<<dp[n];
	return 0;
}
posted @ 2025-12-07 12:26  huhangqi  阅读(0)  评论(0)    收藏  举报