「LibreOJ NOIP Round #1」七曜圣贤

题目啰嗦:
支持三个操作:

不可重复集合:
1.加入一个数

2.删除一个数

3.恢复目前最早的一次删除的数

操作可能不合法,每次有效操作之后求集合的mex(最小没有出现过的数)

 

50组数据+1e6,必须O(N)

 

维护删除、恢复的数的操作可以队列维护。

数有没有在集合里可以全局bool数组记录

 

加入删除一个数,mex怎么维护?

考虑化简问题:
只插入?

直接mex往上走到第一个没有出现的数即可。单增,O(N)

有删除?

如果删除小的一个数,mex要跳下来,然后再恢复这个删除的数,mex又得一步一步走上去。

能不能不跳?

可以!

只要知道当前删除的数最小的一个,和mex取min即可。

维护删除的数的集合:

插入一个数,删除一个数,维护最小的数。怎么看也得带logn

但是,发现恢复数是按照时间顺序从小到大

所以一个数如果比后面的数大,那么直到这个删除的数被恢复也不可能成为最小值。

单调队列维护。

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e6+5;
const int mod=998244353;
int ans[N];
int q[2*N],l,r;
queue<int>que;
int p[N];
bool on[2*N],has[2*N];
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;
void clear(){
    memset(on,0,sizeof on);
    memset(q,0,sizeof q);
    l=1,r=0;
    memset(has,0,sizeof has);
    while(!que.empty()) que.pop();
}
int get(){
    while(l<=r&&on[q[l]]) ++l;
    if(l<=r) return q[l];
    return 0x3f3f3f3f;
}
void upda(int c){
    while(l<=r&&q[r]>=c) --r;
    q[++r]=c;
}
int main(){
    int T;read(T);
    int m,a,b,d;
    while(T--){
        clear();
        init_case(m,a,b,d,p);
        
        for(reg i=0;i<=a;++i) on[i]=1,has[i]=1;
        int mex=a+1;
        for(reg i=1;i<=m;++i){
            int k;
            if(p[i]==-1){//case 3
                if(que.empty()||d){
                    ans[i]=0;goto end;
                }else{
                    k=que.front();que.pop();
                    on[k]=1;
                }
            }else{
                if(!on[p[i]]&&!has[p[i]]){
                    has[p[i]]=1;
                    on[p[i]]=1;
                }else if(on[p[i]]){
                    if(d==1){
                        ans[i]=0;goto end;
                    }else{
                        que.push(p[i]);
                        on[p[i]]=0;
                        upda(p[i]);
                    }
                }else{
                    if(que.empty()||d){
                        ans[i]=0;goto end;
                    }else{
                        k=que.front();que.pop();
                        on[k]=1;
                    }
                }
            }
            while(on[mex]) ++mex;
            ans[i]=min(mex,get());
            end:;
        }
        ll op=0;
        for(reg i=1;i<=m;++i){
            op^=(ll)ans[i]*((ll)i*i%mod+7*i%mod)%mod;
        }
        printf("%lld\n",op);
    }
    return 0;
}
}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/31 16:28:17
*/

 

posted @ 2018-12-31 17:10  *Miracle*  阅读(253)  评论(0编辑  收藏  举报