POJ_3245
这个题目和POJ_3017很像,不过已知的限制条件和求的东西反过来了。
这个题目其实读起来挺费劲的,不过结合他给的HINT还算理解了,建议大家不要去看第一段那几个表达式了,我越看越晕,不知道他在说什么,只要知道分成的几组必须是连续的就行了,然后就可以无视第一段了。
对于第一个限制条件,实际上就是要求对于所有的p<q,且p和q不分在一组,那么必须有Bp>Aq,换句话讲,如果存在p<q且Bp<=Aq,那么p和q就必须分在一组,这样我们就可以把必须分到一起的点连同他们之间的那些点合并看成一个点,然后用sum{Bi}作为这个点的B,用max{Ai}作为这个点的A。
处理完第一个条件后,问题就变成了:把这些点分成若干组,且各个组的Mi之和要满足限制条件,求max{Si}最小是多少,Si表示第i组中各个点的B值之和。
由于Mi之和的限制条件是对于全局而言的,我们没办法在处理局部的时候就保证这个条件始终成立,于是就要换一种思路,不妨二分max{Si}的最小值x,然后将问题转变成:将这些点分成若干组,且每组的B值之和不能超过x,求各个组的Mi之和也就各个组的A的最大值之和最小是多少,并且判断一下是否小于或等于Limit。这样就把这个题转换成POJ_3017那个题了,具体如何求在每组B值之和不能超过x的前提下各个组的A的最大值之和最小是多少,可以参考我的POJ_3017的题解:http://www.cnblogs.com/staginner/archive/2012/04/02/2429850.html。
#include<stdio.h>
#include<string.h>
#define MAXD 50010
int N, M, L, T, node, size[MAXD], left[MAXD], right[MAXD], pool[MAXD], top;
struct Pair
{
int a, b;
}p[MAXD];
int maxa[MAXD], a[MAXD], b[MAXD], q[MAXD], d[MAXD], B[MAXD];
long long int key[MAXD], f[MAXD];
int Max(int x, int y)
{
return x > y ? x : y;
}
int Min(int x, int y)
{
return x < y ? x : y;
}
void leftrotate(int &T)
{
int k = right[T];
right[T] = left[k];
left[k] = T;
size[k] = size[T];
size[T] = size[left[T]] + size[right[T]] + 1;
T = k;
}
void rightrotate(int &T)
{
int k = left[T];
left[T] = right[k];
right[k] = T;
size[k] = size[T];
size[T] = size[left[T]] + size[right[T]] + 1;
T = k;
}
void maintain(int &T, int flag)
{
if(flag == 0)
{
if(size[left[left[T]]] > size[right[T]])
rightrotate(T);
else if(size[right[left[T]]] > size[right[T]])
leftrotate(left[T]), rightrotate(T);
else
return ;
}
else
{
if(size[right[right[T]]] > size[left[T]])
leftrotate(T);
else if(size[left[right[T]]] > size[left[T]])
rightrotate(right[T]), leftrotate(T);
else
return ;
}
maintain(left[T], 0);
maintain(right[T], 1);
maintain(T, 0);
maintain(T, 1);
}
void init()
{
int i, j, k, min, max, sum;
for(i = 1; i <= N; i ++)
scanf("%d%d", &p[i].a, &p[i].b);
maxa[N + 1] = 0;
for(i = N; i > 0; i --)
maxa[i] = Max(p[i].a, maxa[i + 1]);
M = B[0] = 0;
for(i = 1; i <= N; i ++)
{
max = p[i].a, min = p[i].b, sum = p[i].b;
while(i <= N && min <= maxa[i + 1])
{
++ i;
max = Max(p[i].a, max);
min = Min(p[i].b, min);
sum += p[i].b;
}
++ M;
a[M] = max, b[M] = sum;
B[M] = B[M - 1] + b[M];
}
}
long long int Delete(int &T, long long int v)
{
-- size[T];
if(key[T] == v || (v < key[T] && left[T] == 0) || (v >= key[T] && right[T] == 0))
{
int k = key[T];
if(left[T] == 0 || right[T] == 0)
pool[top ++] = T, T = left[T] + right[T];
else
key[T] = Delete(left[T], key[T] + 1);
return k;
}
if(v < key[T])
return Delete(left[T], v);
else
return Delete(right[T], v);
}
void newnode(int &T, long long int v)
{
if(top)
T = pool[-- top];
else
T = ++ node;
key[T] = v;
size[T] = 1;
left[T] = right[T] = 0;
}
void Insert(int &T, long long int v)
{
if(T == 0)
{
newnode(T, v);
return ;
}
++ size[T];
if(v < key[T])
Insert(left[T], v);
else
Insert(right[T], v);
maintain(T, v >= key[T]);
}
long long int searchmin(int &T)
{
if(left[T] == 0)
return key[T];
else
return searchmin(left[T]);
}
int dowell(int limit)
{
int i, j, k, front, rear, decision;
T = node = top = size[0] = left[0] = right[0] = 0;
front = rear = decision = 0;
for(i = 1; i <= M; i ++)
{
while(B[i] - B[decision] > limit)
++ decision;
while(front < rear && q[front] <= decision)
{
Delete(T, f[d[front]] + a[q[front]]);
++ front;
}
while(front < rear && a[q[rear - 1]] <= a[i])
{
Delete(T, f[d[rear - 1]] + a[q[rear - 1]]);
-- rear;
}
q[rear] = i, d[rear] = front < rear ? q[rear - 1] : decision;
Insert(T, f[d[rear]] + a[i]);
++ rear;
if(d[front] < decision)
{
Delete(T, f[d[front]] + a[q[front]]);
d[front] = decision;
Insert(T, f[decision] + a[q[front]]);
}
f[i] = searchmin(T);
}
return f[M] <= L;
}
void solve()
{
int i, max, min, mid;
min = 0;
for(i = 1; i <= M; i ++)
min = Max(b[i], min);
-- min, max = B[M];
for(;;)
{
mid = (max - min + 1) / 2 + min;
if(mid == max)
break;
if(dowell(mid))
max = mid;
else
min = mid;
}
printf("%d\n", max);
}
int main()
{
while(scanf("%d%d", &N, &L) == 2)
{
init();
solve();
}
return 0;
}