7.14T1

一道题连打加调,断断续续写了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 }
View Code
原文地址:https://www.cnblogs.com/hzjuruo/p/11190058.html