Redistricting—— 优先队列+dp

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

输出更赛牛较多的或者均势的分区的最小可能数量。

Sample Input

7 2
HGHGGHG
Sample Output

3

题意:

给你一个串,让你把它分成若干个块,每个块的最大长度为k,问你最后H的数量<=G的数量的块最少的可能是多少。

题解:

这道题一看就是dp,由于它的数据是1e5,那么就不太可能是状压和区间了,那么就是普通dp。dp[i]保存的是在第i个点G的数量>=H的数量的划分的最小区间个数。普通dp有一个特点:后面的状态从前面的状态转移过来。那么这道题到第i个点可以由max(0,i-k)到i-1这个区间的值转移过来,那么由哪里转移过来?肯定是最小值了,否则就不会是最优解。但是最小值有可能有多个,举个例子:
9 6
GGGGGGHGH
这种情况,刚开始六个G都是1,后面的第一个H由于能比前面的任何一个大,所以还是1,之后的G,由于前面的H并没有比它多,所以就变成2了,那么到现在为止dp数组是1 1 1 1 1 1 1 2 0,到最后一个数我们改取什么?肯定是HGH最后3个数,这样就可以消掉一个区间,那么我们要取的是前面G-H最大的那个位置。这样的话后面的H-G会最大,那么优先队列就这样排序就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
char s[N];
int g[N],h[N],dp[N];
struct node
{
    int val,del,id;
    bool operator< (const node& a)const
    {
        if(val!=a.val)
            return val>a.val;
        return del<a.del;
    }
};
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        g[i]=g[i-1]+(s[i]=='G'),h[i]=h[i-1]+(s[i]=='H'),dp[i]=1e9;
    dp[0]=0;
    priority_queue<node>Q;
    Q.push({0,0,0});
    for(int i=1;i<=n;i++)
    {
        int sta;
        if(i<k)
            sta=0;
        else
            sta=i-k;
        while(Q.top().id<sta)
            Q.pop();
        node t;
        t=Q.top();
        dp[i]=t.val+(g[i]-g[t.id]>=h[i]-h[t.id]);
        Q.push({dp[i],g[i]-h[i],i});
    }
    printf("%d\n",dp[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/88092713