解题思路: 回文数组的特性为以数组对称位置的值相等,比如0位和n-1位的值要相等。

  1. 要么相邻两个数同时加或减 或者 只能一个数加或减。

  2. 从1可知,同时加减两个数越多(要都是有效步骤),总步骤就能越少.

  3. 从0和n-1这对数开始,如果p[0]和p[n-1]不相等,那么肯定至少要 (p[0]-p[n-1])(取正值) 次步骤才能使这两数相等。

  4. 然后我们要想这(p[0]-p[n-1])(取正值) 次步骤,能不能为使下一对数p[1]和p[n-2]相等提供帮助,因为第1点我们可以相邻同时加减。由第2点我们可以得出,只要使同时加减次数最多(且有用)即可。

  5. 要使两个数相等,要么使大的数减少,或者使小的数增大。(具体体现为,当只要左边的数大于右边时,即差值(p[0]-p[n-1])大于0,要么增大右边或者减少左边,差值小于0时,增大左边或减少右边。(这句不重要))因为后续在使两数相等时,不需要注重正负(不过代码是需要的),会优先注重大小比较。

  6. 回到第4步,我们计算0和n-1的差值1以及1和n-2的差值2(差值为左边的数减右边,如p[0]-p[n-1],小于0也没事,用if隔开就行)。

  7. 有四种情况,第一种是相等,此时步骤就是差值,且由第3步可知,这是必需的,由2也可知这是最赚的,因为步骤最少。

  8. 第二种情况,当差值1大于差值2,也就是要增大右边或者减少左边,虽然差值2不用这么多次,可差值1要啊,并且由3可知这是必须的,因此我们可以看作在使0和n-1相等时,顺便将1和n-2这对数也相等了,步骤为差值1。

  9. 第三种情况是差值一个大于0一个小于0,此时不能用相邻同时加减了(原因的话有点解释不出,可以写几个数简单推一下)。因此这次步骤就是差值1。但是第二对数(1和n-1)还没相等,要留到下一对数(因为如果差值2和下一对数的差值相等(情况1),或者大于(情况2)就符合规则2,符合最少步骤).

  10. 第四种就是差值1小于差值2,虽然差值1的步骤是必须的,但是小于差值2的那部分呢,这部分会不会和情况3一样说不定能帮下一对数,因此,在步骤依旧是差值1的同时,我们要将 差值2 - 差值1 剩下来的带到下一对数,作为下一次计算的差值1,然后将新一对数的差值为差值2。此时

  11. 此时我们可以把情况1,2,3,4均总结为步骤为差值1(不理解看规则3).情况4和3都会影响下一次的差值1(3 差值1为差值2,4 差值1为差值2 - 差值1)然后以下一对数的差值为差值2。而情况1,2由于两对数都算了,所以需要两对新的数,先来的那对做差值1,后来那对做差值2.

  12. 此时我们就构成了以差值1和差值2的循环,但是我们的循环结构每次都大概率会留一个数给下次算,最终会留下最后一个差值1,因此在考虑循环结束后还要把这个数再算进去。也就是代码最后一个if语句。

  13. 接下来是很麻烦的边界和循环次数。

  14. 当n为偶数时,就是有 n/2 对数要算,循环次数为n/2。n为奇数时,因为最中间那个单身所以要n-1,就是有(n-1)/2对数要算,循环次数为(n-1)/2。可是数组是从0开始的啊。

  15. 原本是1和n,2和n-1这样一一对应,当起始为0时,变为0和n-1,1和n-2,也就是所有数都减1。n为偶数时,最中间的那一对(也就是最后算的那一对)由(n/2和n/2 +1)变为( n/2 -1和n/2 )因此i取值为0到n/2-1,对应位 [n-i-1] 为n-1到n-(n/2-1)-1 =n/2。次数为n/2次。

  16. n为奇数时,中间那一对由( (n-1)/2 和 (n+1)/2 ,比如7就是3对应5,中间的4单身)和( (n-1)/2 -1 和 (n+1)/2 -1 ),由于n为奇数并且计算机的/2向下取整所以 (n-1)/2 -1 可以优化为 n/2 -1 ,也就是省去了n-1,同理(n+1)/2 -1 变为 n/2 ,同样以n等于7为例子,就是3为单身,剩的三对数为 0和6,1和5,2和4。i 取值为0到n/2-1,对应位 [n-i-1] 为n-1到n-(n/2-1)-1 , 因为 n为奇数并且计算机的/2向下取整 ,n/2 实际为(n-1)/2 ,把两个-1化掉原式变为 n-(n-1)/2=(n+1)/2。将上诉n=7带入得到4说明没错。循环次数由 (n-1)/2 也优化为 n/2 。

  17. 最终,终于把循环次数都简化为n/2,i取值为0到n/2-1,对应位 [n-i-1] 为n-1到n/2,也就有了代码中的 for(int i=0;i<n/2;i++)。(实际上你要想偷懒直接挨个试试就能大概知道循环次数)

注意事项: 就因为没把参数范围扩大导致一直不对,气死我了。(因为给的数值大于10的5次方,要用Long int)。


参考代码:

int main(){//3222
	long int n,x=0,sum=0,x1;//x为上一对数的差值,x1为当前这对数的差值,sum用来储存答案即要多少步
	scanf("%ld",&n);
	long int *p=(long int *)malloc(n*sizeof(long int));
	for(int i=0;i<n;i++)scanf("%ld",&p[i]);
	if(n==1){//防止意外,可以省去
		printf("0");
	return 0;
	}
	for(int i=0;i<n/2;i++){
		if(!x) x=p[i]-p[n-i-1];//上一对数相等的情况,也是循环的第一步(将x=p[0]-p[n-1]),也是我们上面写的第3点)
		else {
			x1=p[i]-p[n-i-1];//计算当前这对数的差值
				if(x>0&&x1>0){
				    sum+=x;//将差值1加给sum
					if(x1<=x)x=0;//差值1大于等差值2
					else x=x1-x;//差值1小于差值2
				}
				else if(x<0&&x1<0){
				    sum-=x;//小于0嘛,所以就减了
					if(x1>=x)x=0;//因为都小于0,所以更小的差值更大
					else x=x1-x;
				}
				else {//一个大于0一个小于0的情况,也就是我们上面写的第9点第三种情况
					if(x<0)sum-=x;
					else sum+=x;
					x=x1;
				}
		}
	}
	if(x<0)sum-=x;
	else sum+=x;
	printf("%ld",sum);
	return 0;
}


点赞(1)
 

0.0分

0 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论