【贪心+前缀】C. Fountains

http://codeforces.com/contest/799/problem/C

【题意】

有n做花园,有人有c个硬币,d个钻石 (2 ≤ n ≤ 100 000, 0 ≤ c, d ≤ 100 000) ,每一个花园用三个维度描述(a,b,c),分别是美丽度,所花钱币个数,钱币种类,当然,钱币之间不能兑换,该人必须要建筑两座花园,如果可以,输出两座花园总的美丽度,否则输出0;

【思路】

首先,有三种分类:

 

  • 两座花园一座用钻石,一座用硬币
  • 两座花园都用钻石
  • 两座花园都用硬币

注意两座花园只能同时都买,不能只买一座

第一种情况比较简单,只要找出在两种分类中美丽度分别最大的即可

第二种情况和第三种是类似的,我们只考虑第二种:

首先,价格超过限度的直接省去,然后我们想知道价值和不超过限度的最大美丽度是多少。

我们可以枚举一座花园的价值price1,然后找到另一座满足price2<=c-price1的美丽度最大的花园。

一个很强的做法就是:

按price从小到大排序,for_max数组记录前缀0~i的最大美丽度,只要price[i]满足<=c-price1,就可以i++,最后找到的美丽度一定是最大的。

而且这样做只要一次for循环,price1从后向前枚举,price2的限界一定是增大的,所以只要不断在上一层循环的基础上增加就可以了~

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<vector>
 7 #include<algorithm> 
 8 
 9 using namespace std;
10 const int maxn=1e5+5;
11 typedef pair<int,int> pii;
12 vector<pii> CC,DD;
13 int n,c,d;
14 
15 int Solve(vector<pii> z,int money)
16 {
17      int for_max[maxn];
18      int sz=z.size();
19      sort(z.begin(),z.end());
20      for_max[0]=0;
21      for(int i=1;i<=sz;i++)
22      {
23         for_max[i]=max(for_max[i-1],z[i-1].second);
24     }
25     int i=0;
26     int ans=0;
27     for(int k=sz-1;k>=0;k--)
28     {
29         while(i<k&&z[i].first+z[k].first<=money)
30         {
31                  i++;
32          }
33          i=min(i,k);
34          if(i>0)
35          {
36              ans=max(ans,for_max[i]+z[k].second);
37          }
38          
39     }
40     return ans;
41 }
42 int main()
43 {
44      scanf("%d%d%d",&n,&c,&d);
45      int p,b;
46      int max_c=0,max_d=0;
47      char tag[5];
48      for(int i=0;i<n;i++)
49      {
50         scanf("%d%d%s",&b,&p,tag);
51         if(tag[0]=='C')
52         {
53              if(p>c)
54             {
55                       continue;
56             }
57             CC.push_back(make_pair(p,b));
58             max_c=max(max_c,b);       
59           }
60           else
61           {
62              if(p>d)
63             {
64                       continue;
65             }
66             DD.push_back(make_pair(p,b));
67             max_d=max(max_d,b);
68         }
69     }
70     int ans;
71     if(max_c==0||max_d==0)
72     {
73         ans=0;
74     }
75     else
76     {
77         ans=max_c+max_d;
78     }
79     ans=max(ans,Solve(CC,c));
80     ans=max(ans,Solve(DD,d));
81     printf("%d\n",ans);
82      return 0;
83 }
贪心+前缀

 

转载于:https://www.cnblogs.com/itcsl/p/6912472.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值