习题:Redistricting (单调队列)
习题:
奶牛们的最大城市Bovinopolis正在重新划分势力范围—生活在那里的主要是两个品种的奶牛(Holsteins和Guernseys),他们之间始终都有争执,因为两种奶牛都希望自己能在Bovinopolis的政府中保持足够的影响力。
Bovinopolis的大都市区域由N(1≤N≤3*1e5)个牧场组成,每个牧场包含一头奶牛,她可以是Holsteins,也可以是Guernseys。
Bovinopolis政府希望将大都市区划分为若干个相邻的区域,每个区域最多包含K个牧场(1≤K≤N),每个牧场都恰好只包含在一个区域内。由于目前Bovinopolis政府由Holsteins牛控制,因此,他们希望找到一种重新划分的方法,使得Guernseys牛占多数或两种牛相当的区域尽可能的少(如果Guernseys的数量和Holsteins的数量相同,则认为是两种牛相当)。
有一个关心政治的Guernseys牛的联盟想知道政府的计划会对她们造成多少的伤害,希望你帮助她们计算出Guernseys牛占优或实力相当的区域最小可能的数量。
输入格式
第一行输入2个数字N和K,表示牧场的数量和每个区域最多的牧场数。
第二行输入N个只包含H和G的字符串,表示第i个牧场由Holsteins牛或Guernseys牛控制的牧场。
输出格式
输出Guernseys牛占优或均势的最小分区数量。
样例
样例输入
7 2
HGHGGHG
样例输出
3
思路:
首先如何考虑以O(1)的时间复杂度求出一个区域块里G牛是否占优或者相等,显而易见,将G牛转换成1,H牛转换成-1,用前缀和来求。明白这点之后,DP呼之欲出,但是用纯DP时间复杂度即为O(n^2),虽然时间比起爆搜好了很多,但依旧不能A掉这道题,考虑将DP进行优化,原DP为:dp[i]=min(dp[j]+(s[i]-s[j])>=1?1:0),显而易见,后面一串内容可以使用单调队列来维护(因为作者太懒使用了优先队列)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,summ[300005],dp[300005];
string s;
struct node
{
int x,y;
bool operator < (const node &t) const
{
if(x==t.x) return summ[y]>summ[t.y];
else return x>t.x;
}
} p;
priority_queue<node>q;
int main()
{
// freopen("redistricting.in","r",stdin);
// freopen("redistricting.out","w",stdout);
cin>>n>>k>>s;
for(int i=n; i>=1; i--)
s[i]=s[i-1];
for(int i=1; i<=n; i++)
summ[i]=s[i]=='H'?summ[i-1]+1:summ[i-1]-1;
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
p.x=0;
p.y=0;
q.push(p);
for(int i=1; i<=n; i++)
{
while(!q.empty()&&q.top().y<i-k)
q.pop();
dp[i]=summ[i]-summ[q.top().y]<=0?q.top().x+1:q.top().x;
p.x=dp[i];
p.y=i;
q.push(p);
}
cout<<dp[n];
return 0;
}

浙公网安备 33010602011771号