UVA 1642 MagicalGCD 题解
Posted kamimxr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA 1642 MagicalGCD 题解相关的知识,希望对你有一定的参考价值。
本题是一道区间最大公约数的模板题;
如果N^2暴力的话当然会超时,所以我们要发掘出区间gcd的特点;
设gcd[i]表示区间[1,i]的最大公约数;
我们可以发现,从一个点i到1之间的所有区间的gcd均满足gcd[j]=GCD(gcd[j-1],a[j]);
由于gcd的性质,所以gcd[]是单调不增的;
接着,我们似乎发现了一个更神奇的事情,g[]中不同的值最多有log(max(a[i]))个;
换句话说,虽然g[]数组的长度为n,但在以上两个条件的限制下,最多仅仅有logA个值发生改变的地方;
所以我们遍历一遍右端点,处理出每个i到j(0<=i<=j)的区间的最大公约数;
注意,这并不再是n^2了,因为从i到j在long long 范围内最多有64个不同的值,所以我们只要遍历一遍这些点i就可以知道所有的0<=i<=j到j的区间的gcd;
神奇吧?
综上所述,求出所有区间的gcd仅仅需要nlogA的时间,完全可以切掉这道题;
#include <bits/stdc++.h> #pragma GCC optimize(3) #define ll long long using namespace std; int n; long long a[100010]; long long gcd(long long a,long long b) if(b==0) return a; return gcd(b,a%b); vector<pair<long long ,long long> > vec[100010]; //第一维是值,第二维是在枚举右端点所用的点的编号 int main () cin>>n; for(register int i=1;i<=n;i++) scanf("%lld",&a[i]); for(register int i=1;i<=n;i++) long long x=a[i],y=i; vec[i].push_back(make_pair(x,y)); for(register int j=0;j<vec[i-1].size();j++) if(x==1) break; long long GCD=gcd(x,vec[i-1][j].first); if(GCD!=x) x=GCD; y=vec[i-1][j].second; vec[i].push_back(make_pair(x,y)); long long ans=0; for(register int i=1;i<=n;i++) int w=vec[i].size()-1; for(register int j=0;j<w;j++) pair<long long,long long> p1=vec[i][j]; pair<long long,long long> p2=vec[i][j+1]; ans=max(ans,p1.first*(i-p2.second)); //注意,i-p2.second却不加1的原因是因为该区间其实是[p2.second,i-1]; ans=max(ans,vec[i][vec[i].size()-1].first*i); cout<<ans;
以上是关于UVA 1642 MagicalGCD 题解的主要内容,如果未能解决你的问题,请参考以下文章