CQUPT第十三届ACM网赛 J. 才华横溢 题解

样例输入:
2
2
2 2
4
5 2 3 5
样例输出:
2
5

一丶引入GCD

  GDC,即最大公约数。便捷求法如下。

  

int GCD(int a,int b){
    return !a?b:GCD( b%a , a );
}

二丶对题面的解析。

  我们需要将一个数列分割得到一个最大公约数较大的数列,显然存在N多种割法。同样显然不割的时候GCD最大,也就是本身,但我们需要至少割为两段。

  假设我们将一个字符串已经割了N次,现在将他割为N+1次,我们可以论证GCD不会变大,即不变或者变小。将割了N次的N段数列割为N+1段,显然需要从前面的N段中拿出部分数字来组合成新的一段数列,从数列中拿出数字且最后得到的数段依旧连续,我们有两种方式拿。

  一,从一个连续数列里面拿,若变成了最大公约数更大的几个数列,那么他们合起来也会满足这个更大的最大公约数,故GCD不会变大。

  二,从相邻的两个数列中拿,如果 A,B两个数列分割变成了acb三个数列,且前者的GCD小于后者的GCD,那么我们重新将cb合起来同样满足后来更大的GCD,只能说明AB的割法不优,将AB的割法换成更优的,我们同样可以得出结论,GCD不会随着割数变大而变大。

故这道题便有了解,即分割成2个数列即可,我们用前缀和和后缀和便可以得到这个数列的分割的所有情况,数据量为1e5且a的数据量为1e9,数列和最大为 1e14,我们需要用longlong储存。

代码实现如下

#include<bits/stdc++.h>
using namespace std;

long long int s[100005];//前缀和 
long long int e[100005];//后缀和 
long long int num[100005];//记录数组 

long long GCD( long long a , long long b ){
	
	return !a?b:GCD( b%a , a );
	
}

int main(){
	
	int n;cin>>n;
	
	while( n-- ){
		
		int length;
		cin>>length;
		
		int mem = 0;
		
		for ( int k = 0 ; k < length ; ++k ){	
				cin>>num[k];
				mem+=num[k];
		 		s[k]=mem;
		 }
		 
		 mem = 0;
		 
		 for ( int k = length - 1 ; k >= 0 ; --k ){
		 	
		 	mem+=num[k];
		 	e[k] = mem;
		 	
		 }
		 
		 int min = -1;int gcd = 0;
		 
		 for ( int k = 0 ; k < length - 1 ; ++k ){
		 	
		 	gcd = GCD( s[k] , e[k] - num[k] );
		 	
		 	if ( gcd > min )
				min = gcd;
		 }
		 
		 cout<<min<<endl;
		
	}
	
}			
	
	
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值