• POJ 3245 Sequence Partitioning


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


  • 相关阅读:
    CCF NOI1121 逆波兰表达式
    Vijos P1217 乒乓球【模拟+输入输出】
    Vijos P1304 回文数【回文+进制】
    NUC1041 数字三角形【DP】
    CCF NOI1070 汉诺塔游戏
    CCF NOI1069 分解因数
    CCF NOI1149 N皇后问题
    CCF NOI1153 素数环
    CCF NOI1170 质因数分解
    POJ NOI MATH-7832 最接近的分数
  • 原文地址:https://www.cnblogs.com/staginner/p/2430933.html
Copyright © 2020-2023  润新知