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; }
众人皆醉我独醒,举世皆浊我独清