nowcoder11166G Game of Swapping Numbers(2021牛客暑期多校訓練營1)貪心 抽屜原理
阿新 • • 發佈:2021-07-21
題意
給定兩個等長陣列\(A,B\),任意交換\(A\)中的兩個元素\(K\)次,求\(max\{\sum_{i=1}^N\mid A_i-B_i\mid\}\),\(2\le N\le5×{10}^5,0\le K\le{10}^8,-{10}^8\le A_i,B_i\le{10}^8\)
分析
先考慮交換任意次的情況。求和時,我們考慮去掉絕對值,則相當於為每一對\(A_i,B_i\)分配了一個正號和一個負號。考慮重新分配正負號:由於一對\(A_i,B_i\)的正負號與真實情況相反一定不是更優,那麼對於\(A\)的一個新的排列,交換任意次的最大值就為\(A\),\(B\)兩個數組合並後最大的\(N\)
再由鴿巢原理,在\(N>2\)時,\(A\)中一定有兩個正或兩個負。交換至最大值後,任意正號的數一定大於所有負號的數,對於多餘的次數只需交換兩個正號或者負號,那麼交換次就可以等價於交換至多\(K\)次。\(N=2\)的情況特判即可。
觀察重新分配正負號後的兩個陣列,對於\(A_i,B_i\)一正一負的不需要移動\(A_i\)就可以滿足最大值的狀態,對於兩個正號的需要\(A_i\)與兩個負號的\(A_j\)交換才能滿足最大值。對於一次交換,新增的貢獻為\((A_i+B_i)-(max(A_i,B_i)-min(A_i,B_i))=2*min(A_i,B_i)\)。同理,對於兩個負號新增的貢獻為\(-2*max(A_i,B_i)\)
程式碼
#include <bits/stdc++.h> using namespace std; constexpr int N(5e5+5); using pii=pair<int,int>; int a[N],b[N],x[N]; pii c[N*2]; int main() { int n,k; cin>>n>>k; for(int i=0;i<n;i++) { cin>>a[i]; c[i]={a[i],i}; } for(int i=0;i<n;i++) { cin>>b[i]; c[i+n]={b[i],i}; } sort(c,c+n*2); for(int i=0;i<n;i++) x[c[i].second]--; for(int i=n;i<n*2;i++) x[c[i].second]++; priority_queue<pii>q[2]; long long ans=0; for(int i=0;i<n;i++) { if(x[i]==2) q[0].push({2*min(a[i],b[i]),i}); else if(x[i]==-2) q[1].push({-2*max(a[i],b[i]),i}); ans+=abs(a[i]-b[i]); } int t=q[0].size(); if(n==2) { if(k%2) ans=abs(a[0]-b[1])+abs(a[1]-b[0]); else ans=abs(a[0]-b[0])+abs(a[1]-b[1]); } else { t=min(k,t); while(t--) { ans+=q[0].top().first+q[1].top().first; q[0].pop(); q[1].pop(); } } cout<<ans<<'\n'; return 0; }