D. Cleaning the Phone 二分
题意:给出n个数,这些数代表的是所占用的内存
每一个内存都有一个重要值;
给定一个值m,让我们在重要值消耗最少的情况下,至少腾出m内存
求此重要值
思路:二分
题目给出的重要值,只有1跟2,所以可以把1跟2分别置于不同的数组,并且将每个数组按从大到小排序
然后直接跑二分。
二分check部分,从小到达枚举其中一个数组(另外一个可以通过m值跟枚举的数组推出来)即可(复杂度为n)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=2e5+10; 5 ll a[maxn]; 6 ll b[maxn]; 7 ll tmp1[maxn]; 8 ll tmp2[maxn]; 9 ll sum1[maxn]; 10 ll sum2[maxn]; 11 int num1=0; 12 int num2=0; 13 int n,m; 14 bool cmp1(ll x,ll y) 15 { 16 return x>y; 17 } 18 bool cmp2(ll x,ll y) 19 { 20 return x>y; 21 } 22 ll mnn(ll x,ll y) 23 { 24 if(x<y) return x; 25 else return y; 26 } 27 int check(ll mid) 28 { 29 ll ans=0; 30 for(int i=1;i<=mnn(mid,num1);i++){ 31 ll res=0; 32 res+=sum1[i]; 33 ll tmp=(mid-i)/2; 34 if(tmp>=num2) tmp=num2; 35 res+=sum2[tmp]; 36 ans=max(ans,res); 37 } 38 for(int i=1;i<=num2;i++){ 39 if(2*i>mid) break; 40 ll res=0; 41 res+=sum2[i]; 42 ll tmp=mid-i*2; 43 if(tmp>num1) tmp=num1; 44 res+=sum1[tmp]; 45 ans=max(ans,res); 46 } 47 if(ans>=m) return 1; 48 else return 0; 49 } 50 int main() 51 { 52 int T; 53 scanf("%d",&T); 54 while(T--){ 55 scanf("%d%d",&n,&m); 56 ll tmpsum=0; 57 for(int i=1;i<=n;i++){ 58 scanf("%lld",&a[i]); 59 tmpsum+=a[i]; 60 } 61 ll tmpr=0; 62 num1=num2=0; 63 for(int i=1;i<=n;i++){ 64 scanf("%lld",&b[i]); 65 tmpr+=b[i]; 66 if(b[i]==1) tmp1[++num1]=a[i]; 67 else tmp2[++num2]=a[i]; 68 } 69 if(tmpsum<m) printf("-1\n"); 70 else{ 71 sort(tmp1+1,tmp1+1+num1,cmp1); 72 sort(tmp2+1,tmp2+1+num2,cmp2); 73 for(int i=1;i<=num1;i++){ 74 sum1[i]=sum1[i-1]+tmp1[i]; 75 } 76 for(int i=1;i<=num2;i++){ 77 sum2[i]=sum2[i-1]+tmp2[i]; 78 } 79 ll l=0,r=tmpr; 80 ll ans=-1; 81 while(l<=r){ 82 ll mid=l+r>>1; 83 if(check(mid)){ 84 ans=mid; 85 r=mid-1; 86 } 87 else{ 88 l=mid+1; 89 } 90 } 91 printf("%lld\n",ans); 92 } 93 } 94 return 0; 95 }