• ZOJ 3511 Cake Robbery


    ZOJ_3511

        一种可行的思路就是如果我们把切蛋糕的方案排个序,每次切下来一块就算一下这块的边长,而且这一块必须不会再被切到。

        为了实现上面的思路,我们不妨把每次切的方案记作(x,y),且x<y,那么很显然有一种排序方式是一定符合要求的,即按y-x的值由小到大排序。

        接下来的问题就是怎么算边长了。实际上可以发现边长的数量是等于点的数量,于是我们不妨用线段树记录一下x、y之间点的数量,每切一刀就相当于把x+1、y-1之间所有的点删掉了,这样我们只要查询x、y之间点的数量,就可以将其作为我们当前切下来的这块蛋糕边的数量。最后蛋糕还剩一块没有统计,再看一下最后还剩多少个点就行了。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 100010
    struct Cut
    {
        int x, y;
    }cut[MAXD];
    int N, M, num[4 * MAXD];
    int cmp(const void *_p, const void *_q)
    {
        Cut *p = (Cut *)_p, *q = (Cut *)_q;
        return p->y - p->x < q->y - q->x ? -1 : 1;
    }
    void update(int cur)
    {
        num[cur] = num[cur << 1] + num[(cur << 1) | 1];
    }
    void build(int cur, int x, int y)
    {
        int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
        num[cur] = y - x + 1;
        if(x == y)
            return ;
        build(ls, x, mid);
        build(rs, mid + 1, y);
    }
    void init()
    {
        int i, x, y;
        for(i = 1; i <= M; i ++)
        {
            scanf("%d%d", &x, &y);
            if(x < y)
                cut[i].x = x, cut[i].y = y;
            else
                cut[i].x = y, cut[i].y = x;
        }
        qsort(cut + 1, M, sizeof(cut[0]), cmp);
        build(1, 1, N);
    }
    int query(int cur, int x, int y, int s, int t)
    {
        int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
        if(x >= s && y <= t)
            return num[cur];
        if(mid >= t)
            return query(ls, x, mid, s, t);
        else if(mid + 1 <= s)
            return query(rs, mid + 1, y, s, t);
        else
            return query(ls, x, mid, s, t) + query(rs, mid + 1, y, s, t);
    }
    void refresh(int cur, int x, int y, int s, int t)
    {
        int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
        if(x >= s && y <= t)
        {
            num[cur] = 0;
            return ;
        }
        if(mid >= s)
            refresh(ls, x, mid, s, t);
        if(mid + 1 <= t)
            refresh(rs, mid + 1, y, s, t);
        update(cur);
    }
    void solve()
    {
        int i, j, k, ans = 0;
        for(i = 1; i <= M; i ++)
        {
            k = query(1, 1, N, cut[i].x, cut[i].y);
            if(k > ans)
                ans = k;
            refresh(1, 1, N, cut[i].x + 1, cut[i].y - 1);
        }
        if(num[1] > ans)
            ans = num[1];
        printf("%d\n", ans);
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            if(M == 0)
                printf("%d\n", N);
            else
            {
                init();
                solve();
            }
        }
        return 0;
    }
  • 相关阅读:
    斯坦福机器学习视频之线性回归习题详解
    linuxc程序设计之passwd与shadow解析(转)
    DeepLearning之MLP解析
    The Linux Environment之getopt_long()
    插入排序
    堆排序
    归并排序
    快速排序
    CyclicBarrier与CountDownLatch的区别
    判断是否是平衡二叉树(左子树与右子树高度不大于1)
  • 原文地址:https://www.cnblogs.com/staginner/p/2451871.html
Copyright © 2020-2023  润新知