ZOJ Problem Set - 3655 Alice and Bob

1 篇文章 0 订阅

The 2012 ACM-ICPC Asia Changchun Regional Contest-A


题目大意就是 选出长度为A的一段,是的其中所有长度为A-B的子段的最小值最大。

参见了WJBZBMR大神的解法,地址 http://hi.baidu.com/wjmzbmr/item/8582303e81d7efdd6d15e9cd 

令F[i]=S[i]+...+S[i+A-B-1]  有球s[i]=1 否则为0,那么问题就是求一段长度为A的F数组中的最小值最大是多少。

虽然L R很大,白球很少,这样是的F数组中会有很多连续的值是一样的,把一样的合并成一个即可,然后暴力RMQ询问。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <climits>
#include <numeric>
#include <vector>
#include <set>

#define MK make_pair
using namespace std;
typedef unsigned long long LL;
const int MAXN = 100000+ 10;
pair<LL,int> e[MAXN*2];

LL sum[MAXN * 2];
int tot,cnt,n,N;
LL L,R,A,B,l,r;
LL p[MAXN];
struct Interval {
        LL l, r;
        int cnt;
        Interval() {
        }
        LL len() {
                return r-l+1;
        }
        Interval(LL _l, LL _r, int _cnt) :
                        l(_l), r(_r), cnt(_cnt) {
        }
}q[MAXN*2];

namespace RMQ {                                         // make RMQ;
        const int maxn = 200000 + 10;
        int n, k, a[maxn];
        int rmq[20][maxn];
        void make() {
                for (int j = 0; j < n; ++j)
                        rmq[0][j] = a[j];
                for (int i = 0; i < 20; ++i)
                    for (int j = 0; j + (1 << i) < n; ++j)
                        rmq[i + 1][j]=min(rmq[i][j], rmq[i][j+(1<<i)]);
        }

        int query(int begin, int end) {
                int k = 0;
                while ((1<<(k + 1)) < end-begin)++k;
                return min(rmq[k][begin], rmq[k][end - (1 << k)]);
        }
}

LL getSum(int l, int r) {
        return (l>r?0:sum[r]-(l?sum[l - 1]:0));
}

int main()
{
        while (cin>>N){
              cin>>L>>R>>A>>B;
              for (int i=0;i<N;++i) scanf("%llu",&p[i]);
              B=A-B;
              if (B==0){
                  cout<< 0 << endl;
                  continue;
              }
              cnt=0;
              for (int i=0;i<N; ++i)
              {
                  if (p[i]<=B-1) l=0; else l=p[i]-B+1;
                  r=p[i]+1;
                  if (l<=r) {
                      e[cnt++]=MK(l,1);
                      e[cnt++]=MK(r,-1);
                  }
              }
              sort(e,e+cnt);
              LL nR= R-B+1;
              LL pos = 0;
              int cur = 0;
              int tot=0;
              for (int i=0; i < cnt ;++i)
              {
                  if (e[i].first > 0)
                  {
                      l= max(pos,L);
                      r= min(e[i].first-1,nR);
                      if (l<=r) 
                          q[tot++] = Interval(l,r,cur);
                  }
                  cur += e[i].second;
                  pos= e[i].first;
              }
              if (pos <= nR) {
                  pos = max(pos, L);
                  if (pos <= nR)
                     q[tot++] = Interval(pos, nR, cur);
              }
              for (int i=0;i<tot; ++ i) 
                  RMQ::a[i] = q[i].cnt, sum[i] = q[i].len();
              RMQ::n = tot;
              RMQ::make();
              for (int i=1;i < tot; ++i ) sum[i]+=sum[i-1];
              LL Len = A - B;
              int j = 0, ans = 0;
              for (int i = 0; i < tot; ++i) {
                        for (;;) {
                                LL m = i == j ? 1 : (2 + getSum(j + 1, i - 1));
                                if (Len<m-1) {++j;continue;}
                                break;
                        }
                        for (int x = j; x <= i; ++x) {
                                LL mx = getSum(x, i);
                                if (Len+1<= mx) {
                                        ans = max(ans, RMQ::query(x, i + 1));
                                } else break;
                        }
                }
                cout << ans << endl;
        }
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值