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 ",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 ",ans); 67 } 68 return 0; 69 }