LOJ#538. 「LibreOJ NOIP Round #1」数列递推

    科技2024-07-27  17

    description

    sosusosu 虐爆 OI 之后成为了一名文化课选手。一天,他做作业碰到了一堆数列问题,每道题给出的数列都是以下形式:

    给定一个下标从 0 0 0开始,无限长的整数列 a i {a_{i}} ai i ∈ N i \in N iN ,已知 a 0 , a 1 a_{0},a_{1} a0,a1 的值,以及递推式 a i + 2 = k a i + 1 + a i a_{i+2}=ka_{i+1}+a_{i} ai+2=kai+1+ai i ∈ N i \in N iN k ∈ N + k \in N^+ kN+

    sosusosu 研究了这些数列,发现它们十分优美充满人类智慧,于是决定出一道 OI 题。sosusosu 给了你一个集合 S ⊂ N S\subset N SN,他想问你对于 S S S中的每个数 s i s_i si,使得 a s i a_{s_{i}} asi最大的 s i s_{i} si使得 a s i a_{s_{i}} asi最小的 s i s_{i} si分别是多少。如果这样的 s i s_{i} si有多个,请你回答最小的一个。另外,sosusosu 准备对他作业中碰到的每个数列都让你回答一次,不过每次的集合 S S S是一样的。数列数量 n ≤ 3 ∗ 1 0 5 n\le3*10^5 n3105, S S S中的元素个数 m ≤ 1 0 5 m\le 10^5 m105

    solution

    手玩几组样例,可以得到一个结论:序列在经过某一个临界点之后会变成单调递增或单调递减,且最多只有前 l o g 2 k log_2{k} log2k个数是不单调的,请读者自证我太菜了不会证明故暴力判断前 l o g 2 k log_2{k} log2k个数,然后根据序列的单调性判断 S S S中最大的一个数是最大值还是最小值即可注意如果前 l o g 2 k log_2{k} log2k个数中没有任何一个在 S S S中,那么答案就会是 S 1 S_1 S1,需要特判

    code

    #include<bits/stdc++.h> using namespace std; typedef long long ll; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*f; } const int N=3e5+10; const int M=1e5+10; int m,n,s[M],w[M]; ll a[N]; int main(){ // freopen("ex_seq4.in","r",stdin); m=read(); for(int i=1;i<=m;++i){ s[i]=read(); } n=read(); while(n--){ a[0]=read();a[1]=read(); int k=read(); int fi=min(100,s[m]); ll mx=-1e16,mn=1e16; int mxp=-1,mnp=-1; for(int i=2;i<=fi;++i){ a[i]=1ll*k*a[i-1]+a[i-2]; if(a[i]>1e15&&a[i-1]>=0&&a[i-2]>=0&&a[i]>=0){fi=i;break;} if(a[i]<-1e15&&a[i-1]<=0&&a[i-2]<=0&&a[i]<=0){fi=i;break;} } for(int i=1;i<=m;++i){ if(s[i]<fi){ if(a[s[i]]>mx) mx=a[s[i]],mxp=s[i]; if(a[s[i]]<mn) mn=a[s[i]],mnp=s[i]; } else break; } if(a[fi]>mx&&a[fi]>0)mxp=s[m]; if(a[fi]<mn&&a[fi]<0)mnp=s[m]; if(mxp==-1)mxp=s[1]; if(mnp==-1)mnp=s[1]; printf("%d %d\n",mxp,mnp); } return 0;
    Processed: 0.030, SQL: 10