2021牛客暑期多校训练营1 G.Game of Swapping Numbers(贪心,思维)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营1 G.Game of Swapping Numbers(贪心,思维)相关的知识,希望对你有一定的参考价值。

LINK

考虑不管怎么交换,设最后的数组为 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) (dc)+(fe)

又因为 S 1 S_1 S1中的所有元素必定大于 S 2 S_2 S2中的所有元素(因为在最终的排序后排在前面 n n n个元素)

交换后这两个对的收益是 ( d − e ) + ( c − f ) (d-e)+(c-f) (de)+(cf)

也就是交换后收益多了 2 ∗ ( c − f ) 2*(c-f) 2(cf),也就是多了 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

2021牛客暑期多校训练营 J. Product of GCDs 不动脑子的莫比乌斯反演做法(

2021牛客暑期多校训练营1