BZOJ-4488:最大公约数(GCD)
给定一个长度为 N 的正整数序列Ai对于其任意一个连续的子序列
{Al,Al+1...Ar},我们定义其权值W(L,R )为其长度与序列中所有元素的最大公约数的乘积,即W(L,R) = (R-L+1) ∗ gcd (Al..Ar)。
JYY 希望找出权值最大的子序列。
输入一行包含一个正整数 N。
接下来一行,包含 N个正整数,表示序列Ai
1 < = Ai < = 10^12, 1 < = N < = 100,000
输出文件包含一行一个正整数,表示权值最大的子序列的权值。
Sample Input5 30 60 20 20 20Sample Output80 //最佳子序列为最后 4 个元素组成的子序列
题意:求最大的ans=区间长度*区间最大公约数。
思路:我们考虑到gcd的个数是log级别的,我们对于每个gcd,记录第一个位置即可,开始以为是分治求,这是显然可以的。但事实上没有必要,我们从前向后扫描,当扫描到a[i]时,对于之前的所有gcd,用其第一次出现的位置更新一遍答案,同时把每个gcd和a[i]求gcd,如果第一次出现,则记录其对应位置。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100010; map<ll,int>mp,tp; map<ll,int>::iterator it; int main() { int N,i; ll x,ans=0; scanf("%d",&N); for(i=1;i<=N;i++){ scanf("%lld",&x); ans=max(ans,x); for(it=mp.begin();it!=mp.end();it++){ ll g=__gcd(x,(*it).first); ans=max(ans,(ll)(i-(*it).second+1)*g); if(tp.find(g)==tp.end()) tp[g]=(*it).second; } if(tp.find(x)==tp.end()) tp[x]=i; mp=tp; tp.clear(); } printf("%lld\n",ans); return 0; }
It is your time to fight!