蓝桥杯 2019第十届蓝桥杯 B组J题灵能传输 题解 思路

1.分析题目条件

题中允许对高阶圣堂武士进行的变换操作是 a[ i - 1 ] += a[ i ],a[ i + 1 ] += a[ i ],a[ i ] = - a[ i ]  ,i 属于 [2 , n-1]

需要通过若干次变换操作,得到最小的 max{ | a[ i ] | }

这个变换操作很复杂,不易求解。

2.前缀和形式

尝试转化为前缀和形式,a[ 1 ] ~ a[ n ] 求取前缀和,记为 s[ 1 ] ~ s[ n ]

此时的 a[ 1 ] ~ a[ n ] 变为 s[ 1 ],s[ 2 ] - s[ 1 ],s[ 3 ] - s[ 2 ] …… s[ n ] - s[ n - 1 ]

看看转化后的变换操作

如对 i = 2 使用变换操作 ,那么 s[ 1 ] —> s[ 2 ],s[ 2 ] —> s[ 1 ],s[ 3 ] —> s[ 3 ]

发现对 i 进行变换操作,会导致 s[ i - 1 ] 和 s[ i ] 交换

如此,前缀和形式的变换操作是不是简单的多了!

3.完善前缀和数列

经上分析,我们可以在 s[ 1 ] ~ s[ n - 1 ] 之间的数进行任意交换,使 s[ 1 ],s[ 2 ] - s[ 1 ],s[ 3 ] - s[ 2 ]…,s[ n ] - s[ n - 1 ] 之间差的绝对值的最大值最小

等等!只有第一项是 s[ 1 ] 的形式,后面都是相减的形式,这是不是很难受

补上 s[ 0 ] = 0

这样,我们的题目就转化成为了

在 s[ 1 ] ~ s[ n - 1 ] 之间的数进行任意交换,使 s[ 1 ] - s[ 0 ],s[ 2 ] - s[ 1 ],s[ 3 ] - s[ 2 ]…,s[ n ] - s[ n - 1 ] 之间差的绝对值的最大值最小

4.求解

如果 s[ 0 ] ~ s[ n ] 之间都能随意交换,那差的绝对值的最大值最小显然是排序后,这时数列单调,两个数之差必然是最小哒。

但条件固定了 s[ 0 ] 和 s[ n ] 这两个点!

这意味着固定了起点和终点,要想得到差的最小值当然还是需要排序,但取数就不能是一个一个取了。

排序后起点和终点一般情况就不再是在两端,而是在中间。由于我们要的是差的绝对值,所以我们以 s[ 0 ] 做起点还是以 s[ n ] 做起点都是可以的!

我们设 min{ s[ 0 ],s[ n ] } 做起点,max{ s[ 0 ],s[ n ] }做终点;还需要注意的是特殊情况,即 s[ 0 ] == s[ n ] 时,我们须确保起点的下标要小于终点的下标,不然会发生取数产生重叠区。

如上图所示,取数以起点开始到最小值,再到最大值,最后到达终点。

还有一个问题,那就是上图中存在两段重叠区。重叠区取数也必须要保证向左时和向右时差的绝对值的最大值最小!

隔一个数取一个数显然是最好的解决办法了,向左取数时候就留下了间隔一个数的一组数,留下之后反方向向右取的数。

取数完成后遍历一遍找到差绝对值的最大值,输出。

结束!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5;
ll a[N],s[N];
bool vis[N];
int n;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		memset(vis,0,sizeof(vis));
		scanf("%d",&n);
		s[0]=0;
		for(int i=1;i<=n;++i){
			scanf("%lld",&s[i]);
			s[i]+=s[i-1];
		}
		ll s0=0,sn=s[n];
		if(s0>sn) swap(s0,sn);//前小后大,为方便取数,可避免讨论取数时重复取的问题。 
		sort(s,s+n+1);
		int l=0,r=n;
		for(int i=lower_bound(s,s+n+1,s0)-s;i>=0;i-=2){//隔数取数
			a[l++]=s[i],vis[i]=1;
		}
		for(int i=lower_bound(s,s+n+1,sn)-s;i<=n;i+=2){
			a[r--]=s[i],vis[i]=1;
		}
		for(int i=0;i<=n;++i){
			if(!vis[i]) a[l++]=s[i];
		}
		ll res=0;
		for(int i=1;i<=n;++i)
			res=max(res,abs(a[i]-a[i-1]));
		printf("%lld\n",res);
	}
	return 0;
}

感谢原文,原文链接:原文

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值