【题解】LOJ#541. 「LibreOJ NOIP Round #1」七曜圣贤【乱搞】

题目链接

题意

维护一个集合,初始为 \([0,a]\cap \mathbf{N}\),要求支持以下操作:

  1. 插入 \(x\),保证 \(x\) 未被加入过;
  2. 删除 \(x\)
  3. 把最近一次删除时间最早的、不在集合中的数插入回矩阵。

求每一次操作后集合的 \(\operatorname{mex}\)

多组数据,数据由随机数生成器生成,其中有参数可以控制操作 3 的频率。

\(m\leq 10^6\)\(T\leq 50\)

题解

标算是 \(O(mT)\) 的,这里有一种 \(O(\text{玄学})\) 的做法:

  • 由于数据随机,维护 \(ans\),直接在操作 1、3 时暴力移 \(ans\),操作 2 时 \(ans\gets \min(ans,x)\)
  • 对于 \(c=2\)\(a\) 较大的情况,操作 \(3\) 占了几乎一半,于是集合整体不会被分成很多段,用 set 维护桶的差分。

代码:

#include<bits/stdc++.h>
using namespace std;
long long getint(){
    long long ans=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        ans=ans*10+c-'0';
        c=getchar();
    }
    return ans*f;
}
const int M=2e6+10,mod=998244353;
int m,a,b,c,d;
unsigned int seed;
inline unsigned int randnum(){
    seed^=(seed<<13);
    seed^=(seed>>17);
    seed^=(seed<<5);
    return seed;
}
inline int getp(){
    if(randnum()%c==0)return -1;
    else return randnum()%b;
}

bool f[M<<1],g[M<<1];
int ans=0;
struct que{
    int a[M];
    int *l,*r;
    que(){ l=r=a; }
    inline void push(int x){ *(r++)=x; }
    inline void pop(){ l++; }
    inline int size(){ return r-l; }
    inline void init(){ l=r=a; }
    inline int front(){ return *l; }
};
que q;

set<int>s;
void modi(int x){
	if(s.count(x))s.erase(x);
	else s.insert(x);
}
inline void op1(int p){
	f[p]=g[p]=1;
	if(c>2){
	    while(f[ans])++ans;
	}else{
		modi(p);modi(p+1);
		set<int>::iterator b=s.begin();
		if(*b==0)ans=*(++b);
		else ans=0;
	}
}
inline void op2(int p){
    f[p]=0;
    if(c>2){}else{
		modi(p);modi(p+1);
		if(s.size()){
			set<int>::iterator b=s.begin();
			if(*b==0)ans=*(++b);
			else ans=0;
		}else ans=0;
	}
	q.push(p);
	ans=min(ans,p);
}
inline void op3(){
    op1(q.front());
    q.pop();
}

int main(){
    int T=getint();
    while(T --> 0){
        m=getint(),seed=getint(),a=getint(),b=getint(),c=getint(),d=getint();
		for(int i=0;i<=a;i++)f[i]=g[i]=1;ans=a+1;
		if(c<=2)s.insert(0),s.insert(a+1);
        long long res=0;
        for(int i=1;i<=m;i++){
            int p=getp();
            if(p==-1){
                if(!q.size())continue;
                if(d)continue; else op3();
            }else{
                if(!g[p]){ op1(p); }
                else if(f[p]){ if(d)continue;else op2(p); }
                else if(q.size()){ if(d)continue;else op3(); }
                else continue;
            }
            res^=ans*(i*1ll*i%mod+7ll*i%mod)%mod;
        }
        printf("%lld\n",res);
        q.init();
        memset(f,0,sizeof(bool)*(b+2));
        memset(g,0,sizeof(bool)*(b+2));
        s.clear();
    }
}
posted @ 2020-10-07 17:38  破壁人五号  阅读(163)  评论(0编辑  收藏  举报