[LOJ 541] 七曜圣贤

懒得概括了,,,直接看题面吧

本题 C/C++ 时限 2.5 秒,Pascal 时限 5 秒。最后将改时限重测所有 Pascal 提交。

不知道大家有没有听过物凄系列的一首歌,帕秋莉用卡车给博丽老板运货的故事。

又一次,卡车司机帕秋莉被拜托。红魔馆之主蕾米莉亚喜欢喝红茶,一天她要求帕秋莉开卡车帮她运红茶过来。

红茶其实是编好号了的,每个红茶都用一个非负整数来编号,从 \(0\) 开始一直到正无穷。帕秋莉请来好朋友魔理沙,帮她一起运红茶。

一开始卡车上已经有了编号为 \(0\)\(a\) 的红茶(注意 \(a=-1\) 就表示初始卡车上没有任何红茶),然后接下来到红魔馆的路上有 \(m\) 个时刻,每个时刻都会发生一种事件。

第一种事件,帕秋莉到了一个红茶店,买了一个编号为 \(x\) 的红茶(卡车上初始没有这种编号的红茶,之前也不会买过相同编号的红茶)。

第二种事件,一个目前在卡车上的编号为 \(x\) 的红茶飞出了卡车。

第三种事件,魔理沙把目前不在卡车上的最早飞出去的红茶捡回了卡车上(如果一个红茶曾经飞出去被捡回来过然后再飞出去,这里认为其飞出去的时间为最近一次飞出去的时间)。

由于描述这些事件实在是太麻烦了,聪明的魔理沙用了一个长度为 \(m\) 的整数序列 \(p\) 来描述每个时刻发生的事件。

这个序列 \(p\) 里所有元素均为 \([-1,b)\) 的整数。

\(p_i=-1\) 则表示时刻 \(i\) 发生了第三种事件,如果此时并不存在满足条件的飞出去的红茶,则代表魔理沙脑子没转过来,忽视此次事件。

否则,如果在时刻 \(i\) 编号为 \(p_i\) 的红茶初始不在卡车上也从来没有通过第一种事件买过,则表示时刻 \(i\) 发生了一个买编号为 \(p_i\) 的红茶的第一种事件。

否则,如果在时刻 \(i\) 编号为 \(p_i\) 的红茶在卡车上,则表示时刻 \(i\) 发生了一个编号为 \(p_i\) 的红茶飞出卡车的第二种事件。

否则,表示时刻 \(i\) 发生了第三种事件,如果此时并不存在满足条件的飞出去的红茶,则忽视此次事件。

如果某个时刻的事件被忽视,那么我们不执行对应的操作,也不计算此时的答案

帕秋莉是一个勤奋的人,每个时刻过后,如果这个时刻 \(i\) 发生了事件(如果一个时刻发生的事件被忽视了,就不认为这个时刻发生了事件),令 \(ans_i\) 表示时刻 \(i\) 过后卡车上所有编号小于 \(ans_i\) 的红茶都出现了,而编号为 \(ans_i\) 的红茶没有出现(很显然这个值是唯一的)。当然如果时刻 \(i\) 没有发生事件,则令 \(ans_i=0\)

请你对于 \(1 \leq i \leq m\) 计算出 \(ans_i\times (i^2+7i)\ mod\ 998244353\) 的异或和。

Solution

比较像NOIP2016 D2T2蚯蚓的一道题目。

60pts的做法比较显然,像HEOI2016排序那题的在线做法一样拿一个\(set\)维护所有的区间,动态合并区间,提取区间元素就行了。

考虑\(d=1\)如何做

相当于只有加元素和求\(mex\),维护一个桶表示每个编号是否出现。发现答案是不降的,可以维护一个指针,每次加入后尝试向右移动指针即可。时间复杂度\(O(max(a,b))\)

考虑在\(d=1\)的做法的基础上维护删除和恢复两种操作。

同样维护出加入操作的答案\(x\),和被删除元素的最小值\(y\),容易发现\(mex\)\(min(x,y)\)

如果用堆维护删除元素的最小值,时间复杂度\(O(n\log n)\),期望得分\(70\sim 80\)

如果用单调队列维护删除元素的最小值,时间复杂度\(O(n)\),期望得分\(100\)

Code #include<set> #include<map> #include<cmath> #include<queue> #include<cctype> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using std::min; using std::max; using std::swap; using std::vector; const int N=1e6+5; typedef double db; typedef long long ll; typedef unsigned int uint; #define pb(A) push_back(A) #define pii std::pair<int,int> #define all(A) A.begin(),A.end() #define mp(A,B) std::make_pair(A,B) uint ans,now; int ptr,hd,tail,q[N][2]; int T,m,a,b,d,p[N],remm[N]; int hasbuy[N<<1],isin[N<<1]; namespace IO{ int c; unsigned int seed; unsigned int randnum(){ seed^=seed<<13; seed^=seed>>17; seed^=seed<<5; return seed; } inline int read(int &x){scanf("%d",&x);return x;} inline void init_case(int &m,int &a,int &b,int &d,int p[]){ scanf("%d%u%d%d%d%d",&m,&seed,&a,&b,&c,&d); for(int i=1;i<=m;i++){ if(randnum()%c==0)p[i]=-1; else p[i]=randnum()%b; } } inline void update_ans(unsigned int &ans_sum,unsigned int cur_ans,int no){ const static unsigned int mod=998244353; ans_sum^=(long long)no*(no+7)%mod*cur_ans%mod; } } using IO::read; using IO::init_case; using IO::update_ans; int getint(){ int X=0,w=0;char ch=0; while(!isdigit(ch))w|=ch=='-',ch=getchar(); while( isdigit(ch))X=X*10+ch-48,ch=getchar(); if(w) return -X;return X; } void rem(int x){ isin[remm[x]]=1; while(hd<=tail and q[hd][1]<=x) hd++; } signed main(){ read(T); while(T--){ ans=now=0; int cnt1=0,cnt2=0; memset(isin,0,sizeof isin); memset(hasbuy,0,sizeof hasbuy); init_case(m,a,b,d,p); for(int i=0;i<=a;i++) isin[i]=hasbuy[i]=1; ptr=a+1;hd=1,tail=0; for(int i=1;i<=m;i++){ if(p[i]==-1){ if(d or hd>tail) continue; cnt1++;rem(cnt1); while(isin[ptr]) ptr++; } else if(!hasbuy[p[i]]){ isin[p[i]]=hasbuy[p[i]]=1; while(isin[ptr]) ptr++; } else if(isin[p[i]]){ if(d) continue; cnt2++;remm[cnt2]=p[i]; while(hd<=tail and q[tail][0]>p[i]) tail--; q[++tail][0]=p[i];q[tail][1]=cnt2; isin[p[i]]=0; while(isin[ptr]) ptr++; } else{ if(hd>tail or d) continue; cnt1++;rem(cnt1); while(isin[ptr]) ptr++; } now=ptr; if(hd<=tail) now=min(now,(uint)q[hd][0]); update_ans(ans,now,i); } printf("%u\n",ans); } return 0; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjpfy.html