Juice Extractor(树状数组 + dp)

  Juice Extractor 

Jerry loses himself in the interesting game: Fruit Ninja. Fruit Ninja is a game of iPhone and iPad in which the players cut the fruits coming from the bottom of the screen and gain the bonus from cutting more than two fruits with a single slice. Once a fruit is cut, it breaks into small pieces and cannot be cut any more.

After months of training, he becomes pro of this game. Actually, he can cut all the fruits on the screen at any time. Jerry also has a bad habit that he has no willing to leave some fruits for the future cutting. In the other words, after Jerry cuts the fruits, all the fruits on the screen breaks and no one left. That is why all his friends call him `Juice Extractor'.

Now he only consider about the bonus, when he cuts more than two fruits, he can gain some bonus scores as same as the number of fruits he slice at that time. For example, if Jerry cuts 4 fruits with a single slice, he can get 4 scores from this slice.

After Jerry gets the fruit schedule, he knows the appearing time and the disappearing time for every single fruit. He can only cut a fruit into pieces between its appearing time and disappearing time inclusive. He wants to know the maximum possible bonus scores he can receive.

 

Input 

There are several test cases; the first line of the input contains a single integer T, denoting the number of the test cases. (T$ \le$200)

For each test case, the first line contains an integer N, denoting the total number of fruits. ( 1$ \le$N$ \le$1000)

The next N lines, each line describe a fruit. For each line, there are two integers Xi and Yi, where Xi is the appearing time of the fruit and Yi is the disappearing time of this fruit. ( 0$ \le$Xi$ \le$Yi$ \le$1000000000)

 

Output 

For each test case, output a single integer denoting the maximum scores that Jerry could possibly gain. See the sample for further details.

 

Sample Input 

 

1
10
1 10
2 11
3 12
4 13
13 14
14 15
13 19
20 22
21 23
22 24

 

Sample Output 

 

 

Case #1: 10

 

     题意:

     给出 T组样例,每个样例都有一个 N,代表有 N 个水果。后给出每个水果出现的开始时间和结束时间。在任意一个时间点切水果的话,能够切到所有在这个时间出现的所有水果,当切的水果数 > 2 的时候,才会有得分,得分为所切的水果数,小于等于2得分为0。问如何切,使其分数达到最大。

 

     思路:

     DP + 树状数组。dp [ i ]  = max { dp [ t ] + point (t + 1, i) },dp [ i ] 代表在此刻切水果所达到的最大值,在 i 时刻这刀切的话,在 i 之前出现且尚未消失的水果都会被切除。

     同理 dp [ t ]  代表的也是 t 时刻前的水果都会消失,那么在 (t + 1 , i )这段时间内出现且尚未消失的水果将会在 i 这刀切下去的时候消失,所以最后的得分应该是 dp [ t ] + point ( t + 1, i ) 。

     预处理 dp 应该是只在该时刻切水果所得到的分数,用起点 + 1,(终点 + 1)-1,后 dp [ i ] += dp [ i - 1 ] 可以预处理出来。同时树状数组维护某段时间内的水果数。

 

     AC:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int MAX = 1005;

typedef struct {
    int l, r;
} node;

node no[MAX];
int ans;
int yy[MAX * 2];
int dp[MAX * 2];

int m;
int bit[MAX * 5];

int sum (int x) {
    int s = 0;
    while (x > 0) {
        s += bit[x];
        x -= x & -x;
    }

    return s;
}

void add (int i, int x) {
    while (i <= m) {
        bit[i] += x;
        i += i & -i;
    }
}

int main()
{
    int t;
    scanf("%d", &t);

    for (int tt = 1; tt <= t; ++tt) {
        int n;
        scanf("%d", &n);
        ans = 0;

        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &no[i].l, &no[i].r);
            yy[ans++] = no[i].l;
            yy[ans++] = no[i].r;
        }

        sort(yy, yy + ans);
        ans = unique(yy, yy + ans) - yy;

        m = ans * 5;
        memset(bit, 0, sizeof(bit));
        for (int i = 1; i <= n; ++i) {
            int s = lower_bound(yy, yy + ans, no[i].l) - yy;
            add(s + 1, 1);
        }

        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; ++i) {
            int s = lower_bound(yy, yy + ans, no[i].l) - yy;
            int e = lower_bound(yy, yy + ans, no[i].r) - yy;
            dp[s + 1] += 1;
            dp[e + 2] += -1;
        }

        for (int i = 1; i <= ans; ++i) dp[i] += dp[i - 1];

        for (int i = 1; i <= ans; ++i) {
            dp[i] = dp[i] > 2 ? dp[i] : 0;
        }

        for (int i = 1; i <= ans; ++i) {

            for (int j = 1; j < i; ++j) {
                int ans = sum(i) - sum(j);
                dp[i] = max(dp[i], dp[j] + (ans > 2 ? ans : 0));
            }

            for (int j = 1; j <= n; ++j) {
                int s =  lower_bound(yy, yy + ans, no[j].r) - yy;
                if (s + 1 == i) {
                    int e = lower_bound(yy, yy + ans, no[j].l) - yy;
                    add(e + 1, -1);
                }
            }

        }

        printf("Case #%d: ", tt);
        printf("%d\n", dp[ans]);
    }

    return 0;
}

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值