bzoj 1314: River过河 优先队列

1314: River过河

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 26  Solved: 10
[Submit][Status][Discuss]

Description

ZY 带N个小Kid过河,小KID分成两种:高一年级,高二年级,由于存在代沟问题,如果同一条船上高一年级生和高二年级生数量之差超过K,就会发生不和谐的 事件.当然如果一条船上全是同一年级的,就绝对不会发生争执.现在ZY按小KID队列的顺序依次安排上船,并且不能让他们在过河时发生争执.对于当前等待 上船的小KID来说,要么让他上船,要么将停在渡口的船开走,再让他上另一条船,同一条船上的人不过超过M人.为了让所有的小KID过河,在知悉小KID 队列的情况下,最少需要多少条船.

Input

第一行给出N,M,K.含义如上所述 下行N行用来描述小KID的队列,每行一个字符”A”或者”L”

Output

最少需要多少条船

Sample Input

5 4 1
A
L
L
L
A

Sample Output

2

HINT

前三个人一条船,后两个人一条船
数据范围
30% 数据中1<=N<=1000
100%数据中1<=N<=250000,1<=M,K<=N

 

  这道题过的人这么少不太正常啊。

  容易看出,如果对输入数列换成+1/-1,然后做前缀和,当前dp[i]可以由j-i>=m and abs(a[j]-a[i])<=k 一个矩形内区域的dp值转移出来,首先kdtree肯定没有问题,看有无简单点的做法,思考整体二分,发现不太好处理,注意上述的矩形区域有着固定的宽,而且x坐标单调递增,于是很容易想到对于每一个a[i]维护优先队列了。

  用deque<int>要mle,原因是deque封装了大量维护下标访问的量,而改成list<int>内存要好很多。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<deque>
#include<list>
using namespace std;
#define MAXN 251000
#define lch (now<<1)
#define rch (now<<1^1)
#define smid ((l+r)>>1)
#define MAXT MAXN*4
#define INF 0x3f3f3f3f
int a[MAXN];
int dp[MAXN];
list<int> lst[MAXN];
int sgt[MAXT];
void Modify_sgt(int now,int l,int r,int pos,int v)
{
        if (l==r)
        {
                sgt[now]=v;
                return ;
        }
        if (pos<=smid)
                Modify_sgt(lch,l,smid,pos,v);
        else
                Modify_sgt(rch,smid+1,r,pos,v);
        sgt[now]=min(sgt[lch],sgt[rch]);
}
int Query_sgt(int now,int l,int r,int x,int y)
{
        if (l==x && r==y)
                return sgt[now];
        if (y<=smid)
                return Query_sgt(lch,l,smid,x,y);
        else if (smid<x)
                return Query_sgt(rch,smid+1,r,x,y);
        else
                return min(Query_sgt(lch,l,smid,x,smid),Query_sgt(rch,smid+1,r,smid+1,y));
}
list<int> que;

int main()
{
        freopen("input.txt","r",stdin);
        int n,m,t,x,y,z;
        scanf("%d%d%d\n",&n,&m,&t);
        char ch;
        int level=0;
        int mxvvv=0;
        memset(sgt,INF,sizeof(sgt));
        a[0]=0;
        for (int i=1;i<=n;i++)
        {
                scanf("%c\n",&ch);
                if (ch=='A')
                        a[i]=1;
                else
                        a[i]=-1;
        }
        for (int i=1;i<=n;i++)
                a[i]+=a[i-1];
        for (int i=0;i<=n;i++)
                level=min(a[i],level);
        for (int i=0;i<=n;i++)
                mxvvv=max(a[i],mxvvv);
        level=-level;
        mxvvv+=level;
        for (int i=0;i<=n;i++)
                a[i]+=level;
        dp[0]=0;
        lst[a[0]].push_back(0);
        Modify_sgt(1,0,mxvvv,a[0],dp[lst[a[0]].front()]);
        que.push_back(1);
        for (int i=1;i<=n;i++)
        {
                dp[i]=Query_sgt(1,0,mxvvv,max(0,a[i]-t),min(mxvvv,a[i]+t))+1;
                if (que.size() && a[que.front()]-a[que.front()-1]==a[i]-a[i-1])
                        dp[i]=min(dp[i],dp[que.front()-1]+1);
                while (lst[a[i]].size() && dp[lst[a[i]].back()]>=dp[i])
                        lst[a[i]].pop_back();
                lst[a[i]].push_back(i);
                Modify_sgt(1,0,mxvvv,a[i],dp[lst[a[i]].front()]);
                if (i>=m)
                {
                        if (lst[a[i-m]].size() && lst[a[i-m]].front()==i-m)
                        {
                                lst[a[i-m]].pop_front();
                                if (lst[a[i-m]].size())
                                        Modify_sgt(1,0,mxvvv,a[i-m],dp[lst[a[i-m]].front()]);
                                else
                                        Modify_sgt(1,0,mxvvv,a[i-m],INF);
                        }
                }
                if (i==1 || a[i]-a[i-1]==a[i+1]-a[i])
                {
                        while (!que.empty() && dp[que.back()-1]>=dp[i])
                                que.pop_back();
                        que.push_back(i+1);
                }else
                {
                        while (!que.empty())
                                que.pop_back();
                        que.push_back(i+1);
                }
                if (i-que.front()+1>=m)
                        que.pop_front();
        }
        printf("%d\n",dp[n]);
}

 

转载于:https://www.cnblogs.com/mhy12345/p/4567088.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值