题目如下:
此题思路:
b数组实际上是一个用来分割的数组,即把a数组分成便利值为1和2的两个数组,再分别求前缀和,最后通过枚举前缀和来表示选择多少割1和多少个2。
但要注意
1,用来储存前缀和的数组要开long long。
2,使用lower_bound来加速,如果两个数组都枚举会TLE。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f
const int MAXN=2e5+5;
ll a[MAXN],s1[MAXN],s2[MAXN],d1[MAXN],d2[MAXN];
bool cmp(int a,int b){return a>b;}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,m;
ll sum=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int j=0,k=0;
for(int i=1;i<=n;i++)
{
int op;
cin>>op;
if(op==1)s1[++j]=a[i];
else s2[++k]=a[i];
}
if(sum<m)
{
cout<<-1<<endl;
continue;
}
sort(s1+1,s1+1+j,cmp);
sort(s2+1,s2+1+k,cmp);
for(int i=1;i<=j;i++)
{
d1[i]=d1[i-1]+s1[i];
}
for(int i=1;i<=k;i++)
{
d2[i]=d2[i-1]+s2[i];
}
sum=INF;
for(int i=0;i<=j;i++)
{
if(d1[i]>=m)sum=min(sum,(ll)i);
else
{
int g=lower_bound(d2+1,d2+k+1,m-d1[i])-d2;
if(g==k+1)continue;
sum=min(sum,(ll)(i+g*2));
}
}
cout<<sum<<endl;
}
return 0;
}