【LibreOJ】#541. 「LibreOJ NOIP Round #1」七曜圣贤
【题意】一开始车上有编号为0~a的红茶,过程中出现的红茶编号仅有[0,b),有三种操作:
1.买进编号未在车上出现过的红茶。
2.丢掉车上指定编号的红茶。
3.将最早丢出去的红茶捡回来。
每次操作后求编号最小的不在车上的红茶。
【算法】单调队列
【题解】本题最重要的性质在于早丢早捡。
因此,当进行丢掉编号为x的红茶这一操作时,如果编号>x的红茶早丢,那么也一定早捡,所以这些红茶没有贡献。
所以用单调队列维护所有有效的红茶,那么捡回来的时候判断是否队头,每次答案就是min(队头,maxs+1),maxs是当前已买过的红茶编号。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; 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; const int maxn=2000010; int p[maxn]; bool A[maxn],B[maxn]; int q[maxn],head,tail; queue<int>Q; void ins(int x){ while(head<tail&&q[tail-1]>x)tail--; q[tail++]=x; } int main(){ int T;read(T); int m,a,b,d; while(T--){ unsigned int ans_sum=0,cur_ans=0; init_case(m,a,b,d,p); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); head=0;tail=0; for(int i=0;i<=a;i++)A[i]=B[i]=1; while(!Q.empty())Q.pop(); int ans=a+1,maxs=a; for(int i=1;i<=m;i++){ bool ok=1; if(p[i]==-1){ if(Q.empty()||d)ok=0;else{ int x=Q.front(); A[x]=1;Q.pop(); if(head<tail&&q[head]==x)head++; if(head<tail)ans=min(maxs+1,q[head]);else ans=maxs+1; } } else if(!B[p[i]]){ A[p[i]]=B[p[i]]=1; while(B[maxs+1]){ if(ans==maxs+1)ans++; maxs++; } if(head<tail&&maxs+1>=q[head])ans=q[head]; } else if(A[p[i]]){ if(d)ok=0;else{ Q.push(p[i]);A[p[i]]=0; ins(p[i]); ans=min(ans,q[head]); } } else{ if(Q.empty()||d)ok=0;else{ int x=Q.front(); A[x]=1;Q.pop(); if(head<tail&&q[head]==x)head++; if(head<tail)ans=min(maxs+1,q[head]);else ans=maxs+1; } } if(!ok)cur_ans=0;else cur_ans=ans; update_ans(ans_sum,cur_ans,i); } printf("%u\n",ans_sum); } return 0; }