内存限制:128 MiB
时间限制:1000 ms
题目描述
奶牛们的最大城市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
首先一个长度为k的区间,可以划分为1和k-1,2和k-2…k,很多种选择,
而在这中间每一种选择都会影响答案,
而且与前面一次选择后k具体在哪个到哪个区间有关系
那么这道题就很容易想到DP了,而且长得跟台阶问题很像!
首先我们可以定义一个pre数组,表示1~i区间中,H比G多的个数
如果小于等于0的话,就意味着G占优势,答案+1,大于0则H占优势,答案不变
我们先来处理最容易的DP,dp[i]表示处理完i后的最小答案,很容易就写出:
dp[i] = min ( dp[i], dp[i-j] + ( pre[i] - pre[i - j] ) ≤ 0 ? 1 : 0 )
1≤i≤n,1≤j≤k,
注意理解pre[i]-pre[i-j]实际上算的是[i-j+1,i]
但是这样的dp是O(nk)肯定超时!!
我们得搞点事,做个数据优化啥的!
首先我们每个i只会在外层循环1次,找到1~i-1之前加上i后最小的答案
所以就是求dp[i]=min{dp[i-j] + ( pre[i] - pre[i - j] ) ≤ 0 ? 1 : 0}
这就可以想到堆优化,用优先队列维护,每一次就取队列的top
那么意思是我要维护这个队列一定和i是合法的,
而且对答案的值贡献是从小到大的
来思考一下dp[i-j] + ( pre[i] - pre[i - j] ) ≤ 0 ? 1 : 0
发现 ( pre[i] - pre[i - j] ) ≤ 0 对于答案的影响只有1/0
真正影响的是dp[i-j],所以这个队列我们就可以先维护dp[i-j]从小到大
当dp[i-j]相同时,再维护( pre[i] - pre[i - j] ) ≤ 0从小到大
那么我们就把dp值和下标i丢到队列里,让队列帮我们排序就好啦!
#include
#include
using namespace std;
#define MAXN 300005
int n, k;
char s[MAXN];
int dp[MAXN];
int pre[MAXN];
struct node {
int val, id;
bool operator < ( const node &t ) const {
if ( val == t.val ) return pre[id] > pre[t.id];
return val > t.val;
}
};
priority_queue < node > q;
int main() {
scanf ( "%d %d %s", &n, &k, s );
for ( int i = 1;i <= n;i ++ ){
if ( s[i - 1] == 'H' )
pre[i] = pre[i - 1] + 1;
else
pre[i] = pre[i - 1] - 1;
dp[i] = 0x7f7f7f7f;
}
q.push ( ( node ) { 0, 0 } );
for ( int i = 1;i <= n;i ++ ) {
while ( ! q.empty() && q.top().id < i - k ) q.pop();
dp[i] = ( pre[i] - pre[q.top().id] <= 0 ) ? q.top().val + 1 : q.top().val;
q.push ( ( node ) { dp[i], i } );
}
printf ( "%d", dp[n] );
}
日更爆肝!真爱生命!远离熬夜,保健品你值得拥有
诱人问题都可以留言,我们有缘再见!bye不要太想我我怎么开始满嘴跑火车了?