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;
}