【bzoj4052】[Cerc2013]Magical GCD 暴力
题目描述
给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12。
求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大。
样例输入
1
5
30 60 20 20 20
样例输出
80
题解
暴力
由于$\gcd$具有结合律,所以如果$\gcd(a,b)$比$a$小,那么至少小了一半。
所以所有以一个数为右端点的区间中,本质不同的$\gcd$个数只有$\log a$个。
于是从左向右枚举右端点,统计出以该点为右端点的所有$\gcd$以及区间长度,统计答案;在端点移动时与所有前一个点的$\gcd$再取一个$\gcd$,然后去重即可。
#include <cstdio> #include <cstring> #include <algorithm> #define N 100010 using namespace std; typedef long long ll; ll a[N] , pos[N] , val[N]; int tot; ll gcd(ll a , ll b) { return b ? gcd(b , a % b) : a; } int main() { int T; scanf("%d" , &T); while(T -- ) { tot = 0; int n , i , j , last; ll t , ans = 0; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &a[i]); for(i = 1 ; i <= n ; i ++ ) { last = tot , tot = 0; for(j = 1 ; j <= last ; j ++ ) { t = gcd(val[j] , a[i]); if(t != val[tot]) pos[++tot] = pos[j] , val[tot] = t , ans = max(ans , t * (i - pos[j] + 1)); } if(a[i] != val[tot]) pos[++tot] = i , val[tot] = a[i] , ans = max(ans , a[i]); } printf("%lld\n" , ans); } return 0; }