[ABC376E] Max × Sum 題解

adsd45666發表於2024-10-20

[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\) 的時刻,統計答案。(詳見程式碼)

注:

  1. 記得開 long long
  2. 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;
}

相關文章