洛谷
首先我们设更赛牛为加一,荷斯坦牛为负一。
这样通过前缀和就可以得到这一组是否需要增加一。
设 \(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;
}