1. 程式人生 > >BZOJ2590: [Usaco2012 Feb]Cow Coupons

BZOJ2590: [Usaco2012 Feb]Cow Coupons

ios ide ret fin 最小和 namespace color none close

n<=50000組數Ai,Bi,Ai>=Bi,最多K<=n個組選Bi,其他組選Ai,求最多能選中幾組數使選數總和不超過M<=1e14。

一開始,肯定是在Bi裏面選K個最小的,然後M有剩的再來調整。如何調整呢?現在我有兩個選擇:在沒選的數裏面選個最小的Aj,否則在選的K個最小Bi的裏面,把某個Bi換成Ai,多出一次機會拿沒選的數字中最小的一個Bj。前者可以開個堆或排個序,後者其實是要找Ai-Bi+Bj的最小,開兩個堆分別維護Ai-Bi的最小和Bj的最小即可。

第一次WA:Bj選中後忘了把Aj-Bj加入堆。第二次WA:最後的printf打在了else外也就是輸出了兩個答案。

很好。

技術分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 #include<queue>
 6 //#include<iostream>
 7 using namespace std;
 8 
 9 int n,K;
10 #define LL long long
11 LL t;
12 #define maxn 50011
13 int a[maxn],b[maxn];bool vis[maxn];
14
struct node 15 { 16 int id;LL v; 17 bool operator < (const node &b) const {return v<b.v;} 18 bool operator > (const node &b) const {return v>b.v;} 19 }tb[maxn]; 20 priority_queue<node,vector<node>,greater<node> > qa,qb,qc; 21 int main() 22 { 23 scanf("
%d%d%lld",&n,&K,&t); 24 for (int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),tb[tb[i].id=i].v=b[i]; 25 sort(tb+1,tb+1+n); 26 memset(vis,0,sizeof(vis)); 27 int ans=0; 28 for (int i=1;i<=K;i++) 29 { 30 t-=tb[i].v; 31 if (t<0) break; 32 vis[tb[i].id]=1; 33 ans++; 34 } 35 if (t<0) printf("%d\n",ans); 36 else 37 { 38 for (int i=1;i<=n;i++) 39 if (vis[i]) qc.push((node){i,a[i]-b[i]}); 40 else qa.push((node){i,a[i]}),qb.push((node){i,b[i]}); 41 while (t>=0) 42 { 43 while (!qa.empty() && vis[qa.top().id]) qa.pop(); 44 while (!qb.empty() && vis[qb.top().id]) qb.pop(); 45 if (qa.empty() || qb.empty()) break; 46 int tmp=qb.top().v+qc.top().v; 47 if (tmp<qa.top().v) 48 { 49 t-=tmp; 50 if (t<0) break; 51 ans++; 52 vis[qb.top().id]=1; 53 qc.pop(); 54 qc.push((node){qb.top().id,a[qb.top().id]-b[qb.top().id]}); 55 qb.pop(); 56 } 57 else 58 { 59 t-=qa.top().v; 60 if (t<0) break; 61 ans++; 62 vis[qa.top().id]=1; 63 qa.pop(); 64 } 65 } 66 printf("%d\n",ans); 67 } 68 return 0; 69 }
View Code

BZOJ2590: [Usaco2012 Feb]Cow Coupons