1. 程式人生 > >「NOIP模擬」搶座位【數學】【set判重】

「NOIP模擬」搶座位【數學】【set判重】

官方題解:

因為選出的一段是一個等比序列的子序列,我們分為兩種情況:

q=1q=1,相當於找一個最長每個數都相等的子串,這個掃一遍就行了。

q!=1q!=1,那麼這個序列最長只有 lgn\lg n,那麼我們可以列舉開頭,不妨設開始的兩個數為 a[i]a[i]a[i+1]a[i+1],其中比較大的一個為 xx,另一個 yy

(1) 首先要滿足 x%y=0x\%y=0

(2) 讓 z=xy\displaystyle z=\frac{x}{y},然後把 zz 質因數分解,z=p1q1p2q2p3q3z=p_1^{q_1}*p_2^{q_2}*p_3^{q_3}\cdots

,設 g=gcd(q1,q2,q3 )g=gcd(q_1,q_2,q_3 \cdots),那麼當前序列的最小公比就是 p1q1gp2q2gp_1^{\frac{q_1}{g}}*p_2^{\frac{q_2}{g}}

(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;
}