这要是ACM题又是一道自闭题。。。。。。
原题:
把an表示为p*a0+q*a1的形式,手玩前几项发现不难证明a1系数永远大于a0且越来越大
所以只要这俩别全0,整个数列的走向一定是这样的:
波动->出现相邻同号->起飞
原因很显然,由于a1系数越来越大,所以当n趋向于无穷时a1的符号比a0占优势
而且系数是k的多项式,所以应该飞得很快
担心飞得不够快的可以暴力算各种边界情况,你会发现都会起飞
接下来的难点是将这个规律转化为AC程序,有两个难点
第一个难点是你不知道飞到什么程度才能够保证比前面的都大,我的做法是暴力算前3k个(被卡了,改成300个AC)
第二个难点是爆longlong
我的做法是在暴力的途中,如果发现a[i]>oo(一个很大的数),那么就让a[i]=oo(负数同理)
这样就可以先常规方法找最值点,然后特判一下,如果s[n]已起飞到平流层进入巡航模式,那么就改写最大或最小值点
此外还有很多细节,都标在代码里了,WA了2发才AC,如果是ACM题又要当自闭人力
代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 using ll=long long int; 5 //ll oo=(ll)1000000007*1000000007; 6 ll oo=(ll)1000000007*200000; //warning: k=5e3 7 ll rd(){ 8 ll bwl=0,mk=1; 9 char ch=getchar(); 10 while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 11 if(ch=='-'){ mk=-1; ch=getchar();} 12 while(ch>='0' && ch<='9'){ bwl=bwl*10+ch-'0'; ch=getchar();} 13 return bwl*mk; 14 } 15 int n,m; 16 ll s[310000],a[310000],k; 17 int main(){ 18 n=rd(); 19 for(int i=1;i<=n;++i) s[i]=rd()+1; 20 m=rd(); 21 while(m --> 0){ 22 a[1]=rd(),a[2]=rd(),k=rd(); 23 if(a[1]==0 && a[2]==0){ //warning 24 printf("%lld %lld\n",s[1]-1,s[1]-1); 25 continue; 26 } 27 /* warning: a[1]<0 a[2]<0 a[1]<a[2] 28 if(a[1]<0 && a[2]<0){ 29 printf("%lld %lld\n",s[1]-1,s[n]-1); 30 continue; 31 } 32 if(a[1]>0 && a[2]>0){ 33 printf("%lld %lld\n",s[n]-1,s[1]-1); 34 continue; 35 } 36 */ 37 for(int i=3;i<=300;++i){ 38 a[i]=a[i-1]*k+a[i-2]; 39 if(a[i]>oo) a[i]=oo; 40 if(a[i]<-oo) a[i]=-oo; 41 } 42 if(s[1]>300 || a[s[1]]==oo || a[s[1]]==-oo){ //warning 43 if(a[300]>0) printf("%lld %lld\n",s[n]-1,s[1]-1); 44 else printf("%lld %lld\n",s[1]-1,s[n]-1); 45 } 46 else{ 47 ll mx=s[1],mn=s[1]; 48 for(int i=1;i<=n && s[i]<=300;++i){ 49 if(a[s[i]]>a[mx]) mx=s[i]; 50 if(a[s[i]]<a[mn]) mn=s[i]; 51 } 52 if(a[mx]==oo) mx=s[n]; 53 if(a[mn]==-oo) mn=s[n]; 54 printf("%lld %lld\n",mx-1,mn-1); 55 } 56 } 57 return 0; 58 }View Code