一道题连打加调,断断续续写了11个小时才A掉,是真的心累,想出来的各种时间复杂度低的算法最后被一个O(n2logn)干掉了,其实过了也并没有很开心,毕竟10个小时打O(n),最高才55分,O(n2logn)打了半个小时就干到了WA95,一共也就一个多小时就A掉了,各种错,各种不知道为什么,且搞不到数据的WA,从昨天下午5点一直交到今天下午3点
前面都是废话,我就是想吐吐苦水
关于这道题,首先感谢secret同学强大的证明,那就先说一下关于这个证明,有用到一点求gcd,我不会太严格的证明,有质疑的,或者可以搞出反例的,欢迎diss我
对于两个数x,y(保证较大数可以整除较小数),如果一直拿大数处以小数,留下小数和刚才的商继续除,一直除到两个相等的数,那最后这个数,一定是x,y共同的关于这个数的某次幂,且这个数是可以满足作为x,y的底数的最大数,其实这个除,就是在底数的幂上做gcd,只不过由于最初不知道底数,不能直接给指数gcd,所以利用整个数去除来实现这个过程,不懂的话,自己摆几个例子感性想一下吧,我能力不太够,可能讲不清楚
有了这个东西我们就可以进入这道题了,首先作为一个高考生,应该想到,等比数列应该分为公比为一和公比不为一,为一的话O(n)扫一边肯定没问题,关键就是这个公比不为一的时候,我一直坚强的想要打O(n),一直没成功,结果最后的O(n2)跟他们O(n)一个时间,没A的方法就不多BB了,就说一下这个暴力的O(n2)
既然要构成一个无序的等比数列,那就需要满足序列中每挨着的两个数之间的比值都是公比的几次幂,这个很显然了,不会的直接用等比数列的公式搞一搞,那问题就是找到这个公比,并且判断后面的数是否满足这个公比,满足一直向后推,不满足,更新答案跳出去,这个公比的求法就用到了我一开始说的那个证明,只不过他求得是最大的,而这个公比可能会不停被往小了的方向更新
举个例子对于数列64 8 32 4 2,公比的变化是8,4,4,2
通过这个方法以每个点为起点判就可以了
关于可能会重复,set直接搞定就可以了
1 #include<iostream> 2 #include<cstdio> 3 #include<set> 4 #define ll long long 5 #define maxn 100100 6 using namespace std; 7 int n,i,tot,ans; 8 ll gb; 9 ll a[maxn],chu[maxn]; 10 set <ll> b1; 11 ll CHU(ll x,ll y) 12 { 13 if(x<y) swap(x,y); 14 if(x%y) return -1; 15 ll ans=x/y; return ans; 16 } 17 ll quary(ll x,ll y) 18 { 19 if(x==1||y==1) return max(x,y); 20 while(x!=y) 21 { 22 if(x<y) swap(x,y); 23 if(x%y) return 0; 24 ll da=x/y; 25 x=y; y=da; 26 } 27 return x; 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 for(int j=1;j<=n;++j) 33 { 34 scanf("%lld",&a[j]); 35 if(j==1) continue; 36 chu[j]=CHU(a[j],a[j-1]); 37 } 38 for(int j=1;j<n;++j) 39 { 40 //cout<<"搜索"<<j<<endl; 41 if(chu[j+1]==-1) {/*cout<<"在chu[j+1]==-1处被干掉"<<endl;*/ continue;} 42 b1.clear(); ans=2; gb=chu[j+1]; 43 if(gb==0) {/*cout<<"在gb==0处被干掉"<<endl;*/ continue;} 44 b1.insert(a[j]); b1.insert(a[j+1]); 45 if(a[j]!=a[j+1]) 46 { 47 for(int k=j+2;k<=n;++k) 48 { 49 if(b1.count(a[k])!=0) break; 50 if(chu[k]==-1) break; 51 ll ls=quary(gb,chu[k]); 52 if(ls!=0) {ans++; b1.insert(a[k]); gb=min(gb,ls);} 53 else break; 54 } 55 } 56 else 57 for(int k=j+2;k<=n;++k) 58 { 59 if(a[k]==a[j]) ans++; 60 else break; 61 } 62 tot=max(tot,ans); 63 //cout<<"从"<<j<<"起序列最长长度为"<<ans<<endl; 64 } 65 printf("%d ",tot); 66 return 0; 67 }