P5502 [JSOI2015]最大公約數 題解
阿新 • • 發佈:2020-07-26
簡要題意:
- 給定一個長度為 \(n\) 的序列 \(a\),求出其中一個子串 \(S\),使得 \(|S| \times \gcd(x \in S )\). 求這個最大值。
- 給定一個長度為 \(n\) 的序列 \(a\),求出一個區間 \([l,r]\) 使得 \((r-l+1) \times \gcd_{i=l}^r a_i\) 最大.求這個最大值。
\(n \leq 10^5 , 1 \leq a_i \leq 10^{12}\).
兩種不同表達的題意而已。
首先,丟擲一個非常有用的結論:
- 最大值對應的區間長度不超過 \(\log n\).
為什麼呢?
固定右區間 \(r\)
這樣我們給定 \(r\) 用類似單調佇列的方法維護即可。
時間複雜度:\(\mathcal{O}(n \log n \log a_i)\).
實際得分:\(100pts\).
#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+1; #define L (x<<1) #define R (x<<1)+1 inline ll read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();} ll x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;} inline void write(ll x) { if(x<0) {putchar('-');write(-x);return;} if(x<10) {putchar(char(x%10+'0'));return;} write(x/10);putchar(char(x%10+'0')); } int n; queue<int> q,qq; ll a[N],ans=0; inline ll gcd(ll n,ll m) {return !m?n:gcd(m,n%m);} //計算 gcd signed main() { n=read(); a[0]=-1; for(int i=1;i<=n;i++) { a[i]=read(); int l=0; while(!q.empty()) { int x=q.front(); q.pop(); //printf("%d\n",x); a[x]=gcd(a[x],a[i]); ans=max(ans,a[x]*(i-x+1)); //更新答案 if(a[x] == a[l]) continue; qq.push(x); l=x; //新的決策點 } ans=max(ans,a[i]); while(!qq.empty()) { q.push(qq.front()); qq.pop(); } if(a[l] != a[i]) q.push(i); } write(ans); return 0; }