UVA1642:Magical GCD
题意:
给定一个长度为\(n\leq 10^5\),每个数\(a_i\leq10^{12}\),找一个连续子序列使得子序列的公约数与长度的乘积最大。
\(T\)组数据。
思路:
区间最大公约数模板题。
枚举\((i,j)\)暴力的话时间复杂度为\(O(n^2logn)\),肯定会超时的。
给定序列\(a\),连续子段的\(gcd\)有\(log(max\{a_i\})\)种可能。
\(gcd(1,..,i)=gcd(gcd(1,..,i-1),a(i))\)。
所以每次固定右端点,向左寻找不同\(gcd\)的取值。
#include<bits/stdc++.h> #define PLI pair<long long, int> using namespace std; typedef long long ll; const int maxn = 1e5+10; ll a[maxn]; int n; ll gcd(ll a, ll b) { if(b == 0) return a; return gcd(b, a%b); } //fir->gcd sec->右端点索引 vector<PLI> g[maxn]; void solve() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%lld", &a[i]); g[i].clear(); } for(int i = 1; i <= n; i++) { ll x = a[i], y = i; g[i].push_back({x,y}); for(int j = 0; j < g[i-1].size(); j++) { PLI p = g[i-1][j]; ll t = gcd(x, p.first); if(t != x) { x = t; y = p.second; g[i].push_back({x, y}); } } } ll ans = 0; for(int i = 1; i <= n; i++) { PLI p1, p2; for(int j = 0; j < g[i].size()-1; j++) { p1 = g[i][j]; p2 = g[i][j+1]; ans = max(ans, p1.first*(i-p2.second)); } p1 = g[i][g[i].size()-1]; ans = max(ans, (ll)(i)*p1.first); } cout << ans << endl; } int main() { int T; scanf("%d", &T); while(T--) solve(); return 0; }
来源:https://www.cnblogs.com/zxytxdy/p/12306167.html