http://codeforces.com/contest/799/problem/C
题意:
有n做花园,有人有c个硬币,d个钻石 (2 ≤ n ≤ 100 000, 0 ≤ c, d ≤ 100 000) ,每一个花园用三个维度描述(a,b,c),分别是美丽度,所花钱币个数,钱币种类,当然,钱币之间不能兑换,该人必须要建筑两座花园,如果可以,输出两座花园总的美丽度,否则输出0;
思路:
首先想到分三种情况讨论,两个花园都用硬币,两个花园都用钻石,一个用钻石一个用硬币。
大神的代码真的是很厉害,首先买不起直接省去,接下来先按照价格对花园排序,接下来这个for_max写得很强,记录了第i个之前最大的漂亮度。,接下来进行循环,i从0开始++,然后判断是否满足i<j,然后两座花园所需钱币数量小于目前有的钱币数量,如果满足不断使i++,这样做是满足贪心要求,你目前求得必然是在当前j的条件下最大的,最终求出答案。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 using namespace std; 11 12 const int maxn=100000+5; 13 typedef pair<int,int> pll; 14 15 int n,c,d; 16 vector<pll> CC,DD; 17 int for_max[maxn]; 18 19 int solve(vector<pll> z,int money) 20 { 21 int len=z.size(); 22 if(len<2) return 0; 23 int ans=0; 24 sort(z.begin(),z.end()); //先按照价格排序 25 for_max[0]=0; 26 for(int i=0;i<len;i++) for_max[i+1]=max(for_max[i],z[i].second); //预处理,计算出前i个当中最大的漂亮度 27 int i=0; 28 for(int j=len-1;j>=0;j--) 29 { 30 while(i<j && z[i].first+z[j].first<=money) i++; //因为for_max[i]记录了前i-1个的最大漂亮度,所以只要没超过总价格,就可以一直加上去 31 i=min(i,j); 32 if(i>0) 33 ans=max(ans,for_max[i]+z[j].second); 34 } 35 return ans; 36 } 37 38 int main() 39 { 40 //freopen("D:\input.txt","r",stdin); 41 while(~scanf("%d%d%d",&n,&c,&d)) 42 { 43 CC.clear(); DD.clear(); 44 int cc_max=0,dd_max=0; 45 int ans=0; 46 int b,p; char s[5]; 47 for(int i=0;i<n;i++) 48 { 49 scanf("%d%d%s",&b,&p,&s); 50 if(s[0]=='C') 51 { 52 if(p>c) continue; //买不起的直接省去 53 CC.push_back(make_pair(p,b)); 54 cc_max=max(cc_max,b); 55 } 56 else 57 { 58 if(p>d) continue; 59 DD.push_back(make_pair(p,b)); 60 dd_max=max(dd_max,b); 61 } 62 } 63 if(cc_max!=0 && dd_max!=0) ans=cc_max+dd_max; //第一种情况 64 ans=max(ans,solve(CC,c)); //两个都是硬币 65 ans=max(ans,solve(DD,d)); //两个都是钻石 66 printf("%d ",ans); 67 } 68 return 0; 69 }
另外,树状数组也是可以做的,可以参考http://blog.csdn.net/ssimple_y/article/details/71702915。