[Cerc2013]Magical GCD
https://vjudge.net/problem/UVA-1642
题意:在一个序列中,找出一段连续的序列,使得长度*gcd最大
固定右端点,当左端点从左向右移动时,gcd不变或变大
gcd相同时,序列越长越好
所以相同的gcd只记录最靠左的位置
当右端点由r转移向r+1时
重新计算gcd,然后去重
gcd最多只会有log个
#include<cstdio> #include<iostream> #include<algorithm> #define N 100001 using namespace std; typedef long long LL; LL a[N]; void read(LL &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } struct node { int sum,s[45]; LL gcd[45]; }cur,nxt; LL getgcd(LL a,LL b) { return !b ? a : getgcd(b,a%b); } int main() { int T,n; LL ans,g; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) read(a[i]); cur.gcd[1]=a[1]; cur.sum=cur.s[1]=1; ans=a[1]; for(int r=2;r<=n;r++) { nxt.sum=1; nxt.s[1]=cur.s[1]; nxt.gcd[1]=getgcd(cur.gcd[1],a[r]); for(int l=2;l<=cur.sum;l++) { g=getgcd(cur.gcd[l],a[r]); if(g!=nxt.gcd[nxt.sum]) { ans=max(ans,nxt.gcd[nxt.sum]*(r-nxt.s[nxt.sum]+1)); nxt.sum++; nxt.gcd[nxt.sum]=g; nxt.s[nxt.sum]=cur.s[l]; } } ans=max(ans,nxt.gcd[nxt.sum]*(r-nxt.s[nxt.sum]+1)); if(a[r]!=nxt.gcd[nxt.sum]) { nxt.gcd[++nxt.sum]=a[r],nxt.s[nxt.sum]=r; ans=max(ans,a[r]); } cur=nxt; } printf("%lld\n",ans); } }