「NOIP模擬」搶座位【數學】【set判重】
阿新 • • 發佈:2018-12-18
官方題解:
因為選出的一段是一個等比序列的子序列,我們分為兩種情況:
當 ,相當於找一個最長每個數都相等的子串,這個掃一遍就行了。
當 ,那麼這個序列最長只有 ,那麼我們可以列舉開頭,不妨設開始的兩個數為 和 ,其中比較大的一個為 ,另一個 。
(1) 首先要滿足 。
(2) 讓 ,然後把 質因數分解,,設 ,那麼當前序列的最小公比就是
(3) 我們找到最小公比後,每當往後加一個數,判斷它與前邊的數的比是否是最小公比的整次冪,不是的話就說明不能再加了。
(4)還有一個要求就是這個序列裡不能有重複的數,這個東西用 set 判斷就行了。
#include <set> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define db double #define sg string #define ll long long #define rel(i,x,y) for(ll i=(x);i<(y);i++) #define rep(i,x,y) for(ll i=(x);i<=(y);i++) #define red(i,x,y) for(ll i=(x);i>=(y);i--) #define res(i,x) for(ll i=head[x];i;i=nxt[i]) using namespace std; const ll N=1e5+5; const ll Inf=1e18; const ll Mod=1e9+7; ll n,ans,cnt,a[N],t[N],fac[N]; set<ll>s; inline ll read() { ll x=0;char ch=getchar();bool f=0; while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?-x:x; } void split(ll x) { fac[x]=-1; if(a[x]>a[x-1]) { if(a[x]%a[x-1]==0) { ll tt=a[x]/a[x-1],pp=1;ll cc=-1;bool flag=1; rep(i,2,1000) { ll ret=0; while(tt%i==0) { ++ret;tt/=i; } if(ret) { if(cc==-1) cc=ret; else { if(cc!=ret) { flag=0;break ; } } pp*=i; } } if(tt==1&&flag) { fac[x]=pp;t[x]=cc; } } } else if (a[x]<a[x-1]) { if(a[x-1]%a[x]==0) { ll tt=a[x-1]/a[x],pp=1;ll cc=-1;bool flag=1; rep(i,2,1000) { ll ret=0; while(tt%i==0) { ++ret;tt/=i; } if(ret) { if(cc==-1) cc=ret; else { if(cc!=ret) { flag=0;break ; } } pp*=i; } } if(tt==1&&flag) { fac[x]=pp;t[x]=-cc; } } } } int main() { n=read(); rel(i,0,n) a[i]=read(); rel(i,1,n) split(i); rel(i,0,n) { if(i==0||a[i]==a[i-1]) ++cnt; else { ans=max(ans,cnt);cnt=1; } } ans=max(ans,cnt); rel(i,0,n) { s.clear(); ll q=-1;ll x=0; rel(j,1,n+1-i) { if(s.empty()) s.insert(0); else { if(fac[i+j-1]==-1) break ; if(q==-1) q=fac[i+j-1]; else if (fac[i+j-1]!=q) break ; x+=t[i+j-1]; if(!s.count(x)) s.insert(x),ans=max(ans,j); else break ; } } } printf("%lld",ans); return 0; }