今天老师请了前几届的学长来讲课,可是讲课为什么要考试呢...
学长说难度是NOIP,于是我就naive的跟着参加了,然而T3难度并不友好,感觉确实不是很适合我们现在做......不过课本来也不是给我们这一届讲的?好像逻辑非常自洽的样子。
T1:签到题
题意概述:从一个长度为n的序列中选出一个长度为k的子序列,使得子序列的字典序最大。$n<=1.5*10^7,k<=10^6$
本来想的是一个二维的dp,然而数组开不下,这时候我看向了题目名称:“签到题”,并没有意识到出题人的用意的我坚信这是一道简单题,就真的想出来了...
因为字典序是从前往后比较,如果一个数大后面的就不用再比了,有种贪心的感觉,如果一个数大,就一直往前放,这样不就可以了吗?维护一个单调栈,按照顺序往里面加数,不过还要考虑一个问题,如果这个数虽然非常大,但是太靠后了以至于把它作为第一个后面就无法选出k个数了,那不就....但是还是非常好改的,根据每一个点后面有几个点处理出它最早能插入到哪里就好了。(这个问题竟然是对拍才发现的qwq
1 # include <cstdio> 2 # include <iostream> 3 # define R register int 4 5 using namespace std; 6 7 int Top,x,y,z,n,k; 8 int a[15000009]; 9 int q[1000009]; 10 11 void ins (int x) 12 { 13 while (Top>0&&q[Top]<a[x]&&n-x>=k-Top) Top--; 14 q[++Top]=a[x]; 15 } 16 17 int main() 18 { 19 freopen("red.in","r",stdin); 20 freopen("red.out","w",stdout); 21 22 scanf("%d%d%d%d%d",&x,&y,&z,&n,&k); 23 a[1]=x; 24 for (R i=2;i<=n;++i) 25 a[i]=(long long)a[i-1]*y%z+1; 26 for (R i=1;i<=n;++i) 27 ins(i); 28 for (R i=1;i<=k;++i) 29 printf("%d\n",q[i]); 30 31 fclose(stdin); 32 fclose(stdout); 33 return 0; 34 }