[ABC376E] Max × Sum 題解
原題連結
洛谷連結
一道簡單的推性質題,首先明確一個性質,子集是非連續的,所以在計算時並不用連續區間求。
拿過題來,首先想的是列舉 \(B\) 的最小子集,但其複雜度為 \(O(C_N^K)\) 複雜度過高,不足以透過本題。於是轉變思路,列舉 \(A\) 之中的最大值。若 \(a_i\) 是一個區間最大值,當且僅當長度為 \(k\) 的子集其為最大。但這樣還不是很好求。
由於題目未要求輸出子集元素,則元素順序對求解過程無影響,於是建立結構體陣列 \(s\) 儲存 \(A,B\) ,則有 \(s_i=\{a_i,b_i\}\) ,以 \(a_i\) 的大小進行結構體排序,從大到小遍歷陣列,建立大根堆維護 \(b_i\) 的,若堆的大小超出 \(k\) 則彈出堆頂,和減去。對於每一個堆的大小等於 \(k\) 的時刻,統計答案。(詳見程式碼)
注:
- 記得開
long long
ans
的初值不能太小,至少 \(2e17\)
#include <bits/stdc++.h>
#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long //記得開long long
using namespace std;
const ll maxn = 2e5+10,mod=2e17; //初值至少2e17
ll t,ans;
ll n,k,tot; //tot為b的和
struct node{
ll a,b;
}s[maxn];
bool cmp(node a,node b){ //排序函式
return a.a<b.a;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--){
tot=0,ans=mod;
priority_queue<ll,vector<ll>,less<ll> >pq; //優先佇列儲存b的值
cin>>n>>k;
seq(i,1,n) cin>>s[i].a;
seq(i,1,n) cin>>s[i].b;
sort(s+1,s+n+1,cmp);
seq(i,1,n){
if(pq.size()<k-1){ //若堆的大小不足k-1
tot+=s[i].b;
pq.push(s[i].b);
}
else{
tot+=s[i].b; //壓入,正好k個元素
pq.push(s[i].b);
ans=min(ans,s[i].a*tot); //與原先ans取min
tot-=pq.top(); //不確定是否最優,於是繼續統計
pq.pop();
}
}
cout<<ans<<"\n";
}
return 0;
}