题目传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4878
声明:本人已经退出吉林大学校队,所以不可能参加现场赛了,但是没有退出对算法的热爱,恩,就这样。
题目描述:有个一堆珠子,有白有黑(毫无创意的题目背景....),告诉你白珠子的个数和位置,Alice可以选取一段长为aCount,而Bob可以在Alice选取的段内再选一段长为bCount的都拿走,让留下的所有白珠子最多.....这两人真心无聊啊。
感觉和Ural上面一道题很像......RMQ贴模板......
首先,我们知道,如果aCoutn == bCount那就是0了,其次,如果bCount == 0那么就可以最大子区间了。
一般情况:
假如s[i]表示球的颜色,1为白色,0为黑色。
令F[i] = s[i] + s[i - 1] +.....+ s[i + aCount - bCount - 1]
那么Alice的目的就是让Bob选的在那些F[i]的最小值最大
于是就是求F[i]长为bCount的连续子序列中最小值最大的。
离散化别忘了.....
还有,卡int64....
部分代码:
namespace RMQ
{
int n, k, a[MAXN];
int rmin[20][MAXN];
void make()
{
for (int j = 0; j < n; ++j)
rmin[0][j] = a[j];
for (int i = 0; i + 1 < 20; ++i)
for (int j = 0; j + L(i) < n; ++j)
rmin[i + 1][j] = min(rmin[i][j], rmin[i][j + L(i)]);
}
int query(int begin, int end)
{
int k = 0;
while (L(k + 1) < end - begin)
++k;
return min(rmin[k][begin], rmin[k][end - L(k)]);
}
}
for (int i = 0; i < n; ++i)
{
ll tmp;
if (p[i] <= BC - 1)
tmp =0;
else
tmp = p[i] - (BC - 1);
if (tmp <= p[i] + 1)
{
pr[cnt++] = make_pair(tmp, 1);
pr[cnt++] = make_pair(p[i] + 1, -1);
}
}
sort(pr, pr + cnt);
nt = 0;
nR = R - BC + 1;
for (int i = 0; i < cnt; ++i)
{
ll tmp = pr[i].first;
if (tmp > 0)
{
ll l = max(pos, L);
ll r = min(tmp - 1, nR);
if (l <= r)
t[nt++] = region(l, r, cur);
}
cur += pr[i].second;
pos = tmp;
}
if (pos <= nR)
{
pos = max(pos, L);
if (pos <= nR)
t[nt++] = region(pos, nR, cur);
}
for (int i = 0; i < nt; ++i)
RMQ :: a[i] = t[i].cnt;
RMQ :: n = nt;
RMQ :: make();
sum[0] = t[0].length();
for (int i = 1; i < nt; ++i)
{
sum[i] = t[i].length();
sum[i] += sum[i - 1];
}
ll tmp = AC - BC + 1;
int j = 0;
int ans = 0;
for (int i = 0; i < nt; ++i)
{
for (;;)
{
ll mi = i == j ? 1 : (2 + getsum(j + 1, i - 1));
if (tmp < mi)
{
++j;
continue;
}
break;
}
for (int x = j; x <= i; ++x)
{
ll mx = getsum(x, i);
if (tmp <= mx)
ans = max(ans, RMQ :: query(x, i + 1));
else
break;
}
}
cout << ans << endl;