codeforces 799C(线段树区间更新)

C. Fountains
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Arkady plays Gardenscapes a lot. Arkady wants to build two new fountains. There are n available fountains, for each fountain its beauty and cost are known. There are two types of money in the game: coins and diamonds, so each fountain cost can be either in coins or diamonds. No money changes between the types are allowed.

Help Arkady to find two fountains with maximum total beauty so that he can buy both at the same time.

Input
The first line contains three integers n, c and d (2 ≤ n ≤ 100 000, 0 ≤ c, d ≤ 100 000) — the number of fountains, the number of coins and diamonds Arkady has.

The next n lines describe fountains. Each of these lines contain two integers bi and pi (1 ≤ bi, pi ≤ 100 000) — the beauty and the cost of the i-th fountain, and then a letter “C” or “D”, describing in which type of money is the cost of fountain i: in coins or in diamonds, respectively.

Output
Print the maximum total beauty of exactly two fountains Arkady can build. If he can’t build two fountains, print 0.

Examples
input
3 7 6
10 8 C
4 3 C
5 6 D
output
9
input
2 4 5
2 5 C
2 1 D
output
0
input
3 10 10
5 5 C
5 5 C
10 11 D
output
10
Note
In the first example Arkady should build the second fountain with beauty 4, which costs 3 coins. The first fountain he can’t build because he don’t have enough coins. Also Arkady should build the third fountain with beauty 5 which costs 6 diamonds. Thus the total beauty of built fountains is 9.

In the second example there are two fountains, but Arkady can’t build both of them, because he needs 5 coins for the first fountain, and Arkady has only 4 coins.

题意:有两种货币,然后有n件东西,每件东西有一个美丽值,和一个价格,价格只能是两种货币中的任意一种,然后给你这个人现在有的两种货币的数量,让你买两个东西,使他们的美丽值和最大,如果不能够买到两件东西,则输出0.

解题思路:初一看,有点像背包什么的,仔细一分析,发现是个线段树区间更新,我们分析可得,一共就三种情况,第一种情况,两件东西,一件来自于C货币类型的物品,一件来自于D货币类型的物品,第二种情况,两件东西都来自于C货币类型的物品,第三种情况,两件东西都来自于D货币类型的物品,然后我们三种情况都考虑下,取最大值就行。对于第一种情况,最好办,贪心的找到一个最大美丽值,且能够被买下的就行。第二种情况和第三种情况是一样的,我们就一起分析,也就是问题变成了在一堆物品中找两个物品,在他们的总价格不超过我们手中的货币情况下使他们的美丽值和最大。因为只需要找两个,我们从第一个物品扫到最后一个物品就行,中间我们用线段树维护一个价格为x的最大可以加上的美丽值就行,具体思路看代码。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n,c,d;
struct node{
    int b;
    int p;
};
struct tree{
    int l;
    int r;
    int value;
    int add;
}Tree[4*maxn];
node Node1[maxn];
node Node2[maxn];
int cnt1;//c
int cnt2;//d
void add(int b,int p,char ch)
{
    if(ch == 'C')
    {
        node nx;
        nx.b = b;
        nx.p = p;
        Node1[++cnt1] = nx;
    }
    else
    {
        node nx;
        nx.b = b;
        nx.p = p;
        Node2[++cnt2] = nx;
    }
}
void pushDown(int i)
{
    int f1 = i<<1;
    int f2 = f1 + 1;
    Tree[f1].value = max(Tree[f1].value,Tree[i].add);
    Tree[f1].add = max(Tree[f1].add,Tree[i].add);
    Tree[f2].value = max(Tree[f2].value,Tree[i].add);
    Tree[f2].add = max(Tree[f2].add,Tree[i].add);
    Tree[i].add = -1;
}
void build(int i,int l,int r)
{
    Tree[i].l = l;
    Tree[i].r = r;
    Tree[i].value = -1;
    Tree[i].add = -1;
    if(l == r)
    {
        return;
    }
    int f = i<<1;
    int mid = (l + r)>>1;
    build(f,l,mid);
    build(f + 1,mid + 1,r);
}
void update(int i,int l,int r,int value)
{
    if(Tree[i].l == l&&Tree[i].r == r)
    {
        Tree[i].value = max(Tree[i].value,value);
        if(l == r)
        {
            Tree[i].add = -1;
        }
        else
        {
            Tree[i].add = max(Tree[i].add,value);
        }
        return;
    }
    if(Tree[i].add != -1)
    pushDown(i);
    int f = i<<1;
    if(r <= Tree[f].r) update(f,l,r,value);
    else if(l >= Tree[f + 1].l) update(f + 1,l,r,value);
    else
    {
        update(f,l,Tree[f].r,value);
        update(f + 1,Tree[f + 1].l,r,value);
    }
}
int query(int i,int l,int r)
{
    if(Tree[i].l == l&&Tree[i].r == r) return Tree[i].value;
    if(Tree[i].add != -1) pushDown(i);
    int f = i<<1;
    if(r <= Tree[f].r) return query(f,l,r);
    else if(l > Tree[f].r) return query(f + 1,l,r);
    else return max(query(f,l,Tree[f].r),query(f + 1,Tree[f + 1].l,r));
}
void init()
{
    cnt1 = 0;
    cnt2 = 0;
}
int main()
{
    while(~scanf("%d%d%d",&n,&c,&d))
    {
        init();
        int B,P;
        char C;
        for(int i = 1; i <= n; i++)
        {
            cin>>B>>P>>C;
            add(B,P,C);
        }
        int Max = 0;
        int ans1 = -1;
        int ans2 = -1;
        for(int i = 1; i <= cnt1; i++)
        {
            if(c >= Node1[i].p) ans1 = max(ans1,Node1[i].b);
        }
        for(int i = 1; i <= cnt2; i++)
        {
            if(d >= Node2[i].p)
            {
                ans2 = max(ans2,Node2[i].b);
            }
        }
        if(ans1 != -1&&ans2 != -1) Max = max(Max,ans1 + ans2);
        build(1,1,100000);
        for(int i = 1; i <= cnt1; i++)
        {
            B = Node1[i].b;
            P = Node1[i].p;
            int x = query(1,P,P);
            if(x != -1)
            {
                Max = max(Max,B + x);
            }
            if(c - P >= 1)
            update(1,1,c - P,B);
        }
        build(1,1,100000);
        for(int i = 1; i <= cnt2; i++)
        {
            B = Node2[i].b;
            P = Node2[i].p;
            int x = query(1,P,P);
            if(x != -1)
            {
                Max = max(Max,B + x);
            }
            if(d - P >= 1)
            update(1,1,d - P,B);
        }
        printf("%d\n",Max);
    }
    return 0;
}

区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值