2021牛客暑期多校训练营1 G.Game of Swapping Numbers(贪心,思维)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营1 G.Game of Swapping Numbers(贪心,思维)相关的知识,希望对你有一定的参考价值。
考虑不管怎么交换,设最后的数组为 a a a数组
考虑绝对值的含义, a i a_i ai和 b i b_i bi一定有一个被加上,一个被减去
那么如果不固定 k k k的取值,最优情况相当于把 a , b a,b a,b数组合并排序一下
前 n n n大的数就把正号赋给他们,后面 n n n个数就把负号赋给他们,这样是最优的
所以考虑一对 ( a i , b i ) (a_i,b_i) (ai,bi),在最优解中被赋的正负号不同,那么就不需要管.因为这种情况下较大的那个数被赋的一定是正号,较小的那个数被赋的一定是正号
于是我们只需要考虑哪些 a i , b i a_i,b_i ai,bi同时被赋为正(设这样的对的集合为 S 1 S_1 S1)或同时赋为负号的对(设这样的集合为 S 2 S_2 S2)
显然我们每次交换 S 1 S_1 S1和 S 2 S_2 S2即可以最小步数达到最优解,设需要交换 z z z次( z z z即 S 1 S_1 S1中的元素个数)
若 k > = z k>=z k>=z,那么一定是能达到最优解的,因为最优解中 a a a中一定存在两个 + + +号或两个 − - −号,交换这样的对答案不变
若 k < z k<z k<z,考虑怎样交换会比较好
设 S 1 S_1 S1中的一个对为 a i , b i a_i,b_i ai,bi其中较小数为 c c c较大数为 d d d
而 S 2 S_2 S2中的元素为 a j , b j a_j,b_j aj,bj,其中较小数为 e e e较大数为 f f f
那么交换前这两个对之前收益是 ( d − c ) + ( f − e ) (d-c)+(f-e) (d−c)+(f−e)
又因为 S 1 S_1 S1中的所有元素必定大于 S 2 S_2 S2中的所有元素(因为在最终的排序后排在前面 n n n个元素)
交换后这两个对的收益是 ( d − e ) + ( c − f ) (d-e)+(c-f) (d−e)+(c−f)
也就是交换后收益多了 2 ∗ ( c − f ) 2*(c-f) 2∗(c−f),也就是多了 2 ∗ ( m i n ( a i , b i ) − m a x ( a j , b j ) ) \\rm 2*(min(a_i,b_i)-max(a_j,b_j)) 2∗(min(ai,bi)−max(aj,bj))
于是同样是交换 k k k次, S 1 S_1 S1我们以 min ( a i , b i ) \\min(a_i,b_i) min(ai,bi)为依据大到小排序,而 S 2 S_2 S2以 m a x ( a j , b j ) \\rm max(a_j,b_j) max(aj,bj)以小到大为依据排序
这样从前往后交换对应的位置一定最优
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e7+10;
int n,k,a[maxn],b[maxn],f[maxn];
typedef pair<int,int>p;
struct RR
{
int val,id;
bool operator < ( const RR&tmp ) const { return val>tmp.val; }
}S[maxn]; int top;
vector<int>S1,S2;
void solve()
{
if( n==2 )
{
if( k&1 ) swap( a[1],a[2] );
cout << abs( a[1]-b[1] )+abs( a[2]-b[2] );
exit( 0 );
}
int ans = 0;
for(int i=1;i<=n;i++) ans += S[i].val;
for(int i=1;i<=n;i++) ans -= S[i+n].val;
cout << ans;
exit( 0 );
}
signed main()
{
cin >> n >> k;
for(int i=1;i<=n;i++) cin >> a[i],S[++top] = {a[i],i};
for(int i=1;i<=n;i++) cin >> b[i],S[++top] = {b[i],i+n};
sort( S+1,S+1+top );
for(int i=1;i<=top;i++) f[S[i].id] = (i<=n);
for(int i=1;i<=n;i++)
{
if( f[i]!=f[i+n] ) continue;//不同号
if( f[i] ) S1.push_back( min(a[i],b[i]) );//都是正号
else S2.push_back( max(a[i],b[i]) );//都是负号
}
if( k>=S1.size() ) solve();//完美匹配
sort( S1.begin(),S1.end(),[](int a,int b){ return a>b; } );
sort( S2.begin(),S2.end(),[](int a,int b){ return a<b; } );
int ans = 0;
for(int i=1;i<=n;i++) ans += abs( a[i]-b[i] );
for(int i=0;i<k;i++) ans += 2*( S1[i]-S2[i] );
cout << ans;
}
以上是关于2021牛客暑期多校训练营1 G.Game of Swapping Numbers(贪心,思维)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营2——Product of GCDs
2021牛客暑期多校训练营10 War of Inazuma (Easy Version)(二分图)
2021牛客暑期多校训练营5K King of Range(单调队列)
2021牛客多校1 G Game of Swapping Numbers