洛古题解之P8480

(题目传送门)

题目描述(此处简化了亿点点)

给出一个长为n的整数序列a_{i},并给这个序列进行m次操作,每次操作可以任意选择序列中一个数 a_{i},令a_{i}变成a_{i}+2a_{i}-2a_{i}*2\left \lfloor \frac{a_{i}}{2} \right \rfloor这四个结果中的一个。最终希望m次操作后整个序列的极差最大。

输入格式

第一行两个整数n,m

第二行n个整数,表示序列 a_{i}

输出格式

共一行

一个整数,表示最大的极差

输入输出样例

输入

3 2
0 1 0

输出

6

数据范围

对于100%的数据,1<n<10^6+1,0<m<11,0<a_{i}<10^9

以上是题目部分;以下是题解部分:

设当前的最大值为mx,最小值为mn。为了让极差变大,我们显然是只操作这两个数。并且一定是让mx变大,mn变小。所以我们只可能进行这四个操作:

        1.mx:=mx+2

        2.mx:=mx*2

        3.mn:=mn-2

        4.mn:=\left \lfloor \frac{mn}{2} \right \rfloor

下面我们就来考虑那种操作对答案的贡献更大:设一次操作对答案的贡献f_{x}。那么这四种操作的贡献分别为:

        1.f_{1}=2

        2.f_{2}=mx

        3.f_{3}=2

        4.f_{4}=mn-\left \lfloor \frac{mn}{2} \right \rfloor

显然有f_{4}\leqslant mn\leqslant mx=f_{2}。所以f_{4}不可能进行。也就意味着如果我们改变最小值,每次操作最多将答案+2。而如果改变最大值,每次操作至少可以让答案+2。所以我们只要操作最大值就可以了。下面我们考虑如何选取f_{1}f_{2}操作。不难发现,当 mx>2时,进行f_{2}操作更优。当 mx=2时,两种操作效果一样。当mx<2时,进行f_{1}操作更优。并且当进行一次f_{1}操作后必然有mx>1。所以我们只需要记录初始序列的最大值和最小值,如果最大值小于2,就先将其+2,然后不断的对最大值进行*2操作即可。

C语言:

#include<stdio.h>
long long n,m,x,maxx=0,minx=1e9;
int main() {
	scanf("%lld %lld",n,m);
	for(long long i=0;i<n;i++) {
		scanf("%lld",x);
		if(x>maxx) {
            maxx=x;
        }
		if(x<minx) {
            minx=x;
        }
	}
	if(maxx<2) {
        maxx+=2;
        m--;
    }
	printf("%lld",((1ll*maxx)<<m)-minx);
	return 0;
}

C++: 

#include<iostream>
using namespace std;
long long n,m,x,maxx=0,minx=1e9;
int main() {
	cin>>n>>m;
	for(long long i=0;i<n;i++) {
		cin>>x;
		if(x>maxx) {
            maxx=x;
        }
		if(x<minx) {
            minx=x;
        }
	}
	if(maxx<2) {
        maxx+=2;
        m--;
    }
	cout<<((1ll*maxx)<<m)-minx;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/FlyFree56/article/details/126586540