2025.8.15 CSP-S模拟赛35

波波说知识点跟不上的可以不用每场都打……所以我昨天那场没打:)喜

T1 114514 (好臭的名字

波波连题面都懒得放了,所以这个链接的唯一作用是让你再跳转到模拟赛界面然后下载PDF;

赛时最先想到了mex,但是手模之后感觉不是很对,不过差不多;

因为要求字典序最小,那么对于一个数,如果这个数不与之前的数接轨,也就是开启一个新的连续段的话,那么这个数在原序列中也是一样的,所以它没有贡献;否则如果它与其之前的连续段接壤,它的贡献就是整个包括其本身的连续断的长度加一,不想写公式了,直接看代码理解吧;

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e6+10,MAXM=4e6+10;
const int mod=1e9+7;
int n,xb=1,f[MAXM];
vector<int> a;
set<int> c;
int t[MAXM],cnt;
int ans=1;
int find(int x){
	return (x==f[x]?x:f[x]=find(f[x]));
}
signed main(){
	freopen("trans.in","r",stdin);
	freopen("trans.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1,x;i<=n;i++){
		cin>>x;
		a.push_back(x);
		if(!t[x-1]) f[x]=x;
		else{
			f[x]=f[x-1];
			ans*=(x-find(f[x])+1);
			ans%=mod;
		}
		if(t[x+1]) f[x+1]=f[x];
		t[x]=1;
	}
	cout<<ans%mod;
	return 0;
} 

赛时半个小时写出T1,感觉剩下的时间都在罚坐,还是太菜了;

T2 沉默乐园

赛时只写出了十分暴力,其实对于 \(l_i,r_i\) 固定的那一部分,是可以打表推式子搞出来的,但是赛时心态比较有问题所以没有成功;

题解已经说得很清楚了,设 \(f_{i,j,0/1,k}\) 表示左边已经选了 \(i-1\) 个数,右边选了 \(j-1\) 个数,左边/右边更大,比另外一边大 \(k\) 的方案数,这里设 \(m= max r_i\)

那么转移非常显然:

\[f_{2,n,0,k}=[k \in [l_1,r_1]] \\ \]

\[f_{1,n-1,1,k}=[k \in [l_n,r_n]] \\ \]

\[f_{i,j,0,k} \rightarrow f_{i+1,j,0,k+x}(x \in [l_i,r_i],k+x \leq m)\\ \]

\[f_{i,j,0,k} \rightarrow f_{i,j-1,1,x-k}(x \in [l_j,r_j],x-k \geq 1)\\ \]

\[f_{i,j,1,k} \rightarrow f_{i,j-1,1,k+x}(x \in [l_j,r_j],k+x \leq m)\\ \]

\[f_{i,j,1,k} \rightarrow f_{i+1,j,0,x-k}(x \in [l_i,r_i],x-k \geq 1)\\ \]

\[(r_i-k-max(l_i-k,1)+1)(f_{i,i,0,k}+f_{i,i,1,k}) \rightarrow ans \]

LATEX敲得好累

前六个转移方程应该是极好理解的,对于最后一个,第一个系数是为了保证经过这次修改之后两个真前缀不相等的选择方案数;对于为什么转移时不考虑真前缀和真后缀的差大于 \(m\) 的情况,因为如果转移到这种情况,一定存在一种方案将其转换至等价于差值不大于 \(m\) 的一种情况,如果再计算就会多算答案,所以不用考虑

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int MAXN=55,MAXM=2e3+5;
struct fio{
	#define isdigit(x) (x >= '0' && x <= '9')
	char buf[1 << 20], *p1, pbuf[1 << 20], *p2, *pp;
	fio() : p1(buf), p2(buf), pp(pbuf){}
	~fio(){fwrite(pbuf, 1, pp - pbuf, stdout);}
	inline char gc(){return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1 ++;}
	inline void pc(const char &c){if (pp - pbuf == 1 << 20) fwrite(pbuf, 1, 1 << 20, stdout), pp = pbuf;*pp ++ = c;}
	inline bool blank(char ch){return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';}
	template <class T> inline void read(T &x){
		long double tmp = 1;bool sign = 0;char ch = gc();x = 0;
		for (;!isdigit(ch);ch = gc()) if (ch == '-') sign = 1;
		for (;isdigit(ch);ch = gc()) x = x * 10 + (ch - '0');
		if (ch == '.') for (ch = gc();isdigit(ch);ch = gc()) tmp /= 10.0, x += tmp * (ch - '0');
		if (sign) x = -x;
	}
	inline void read(char *s){
    	char ch = gc();for (;blank(ch);ch = gc());
    	for (;!blank(ch);ch = gc()) *s ++ = ch;*s = 0;
    }
    inline void read(char &c){for (c = gc();blank(c);c = gc());}
	template <class T> inline void write(T x){
		if (x < 0) x = -x, pc('-');int sta[30];int top = 0;
		do sta[top ++] = x % 10, x /= 10;while (x);
		while (top) pc(sta[-- top] + '0');
	}
}io;
struct node{
	int l,r;
}q[MAXN];
int cf[55][55][2][MAXM];
int n,m,f[55][55][2][MAXM],ans;
signed main(){
	freopen("orchestra.in","r",stdin);
	freopen("orchestra.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>q[i].l>>q[i].r;
		m=max(m,q[i].r);
	}
	if(n==1){
		cout<<q[1].r-q[1].l+1;
		return 0;
	}
	cf[2][n][0][q[1].l]+=1,cf[2][n][0][q[1].r+1]-=1;
	cf[1][n-1][1][q[n].l]+=1,cf[1][n-1][1][q[n].r+1]-=1;
	for(int i=1;i<=n;i++){
		for(int j=n;j>=i;j--){
			for(int k=1;k<=m;k++) f[i][j][0][k]=(f[i][j][0][k-1]+cf[i][j][0][k])%mod,f[i][j][1][k]=(f[i][j][1][k-1]+cf[i][j][1][k])%mod;
			for(int k=1;k<=m;k++){
				if(min(q[i].r,m-k)>=q[i].l){
					cf[i+1][j][0][q[i].l+k]=(cf[i+1][j][0][q[i].l+k]+f[i][j][0][k])%mod;
					cf[i+1][j][0][min(q[i].r,m-k)+k+1]=(cf[i+1][j][0][min(q[i].r,m-k)+k+1]-f[i][j][0][k]+mod)%mod;
				}
				if(q[i].r>=max(q[i].l,1+k)){
					cf[i+1][j][0][max(1+k,q[i].l)-k]=(cf[i+1][j][0][max(1+k,q[i].l)-k]+f[i][j][1][k])%mod;
					cf[i+1][j][0][q[i].r-k+1]=(cf[i+1][j][0][q[i].r-k+1]-f[i][j][1][k]+mod)%mod;
				}
				if(min(q[j].r,m-k)>=q[j].l){
					cf[i][j-1][1][q[j].l+k]=(cf[i][j-1][1][q[j].l+k]+f[i][j][1][k])%mod;
					cf[i][j-1][1][min(q[j].r,m-k)+k+1]=(cf[i][j-1][1][min(q[j].r,m-k)+k+1]-f[i][j][1][k]+mod)%mod;
				}
				if(q[j].r>=max(q[j].l,1+k)){
					cf[i][j-1][1][max(1+k,q[j].l)-k]=(cf[i][j-1][1][max(1+k,q[j].l)-k]+f[i][j][0][k])%mod;
					cf[i][j-1][1][q[j].r-k+1]=(cf[i][j-1][1][q[j].r-k+1]-f[i][j][0][k]+mod)%mod;
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int k=1;k<=q[i].r;k++){
			ans+=(q[i].r-k-max(q[i].l-k,1ll)+1)*(f[i][i][0][k]+f[i][i][1][k])%mod;
			ans%=mod;
		}
	} 
	cout<<ans;
	return 0;
}

T3 深黯

这个我讲的肯定不是很好,建议直接移步超级无敌wyl大王的题解

也可以时坠机zhangxy的题解

代码放下面,题解不懂得可以看代码注释:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=5e5+10;
int n,m,mod,a[MAXN],fac[MAXN];
int tr[MAXN];
int lowbit(int x){
	return (x&(-x));
}
void add(int x,int val){
	for(int i=x;i<=n;i+=lowbit(i))
		tr[i]+=val;
	return ;
}
int query(int x){
	int res=0;
	for(int i=x;i;i-=lowbit(i))
		res+=tr[i];
	return res;
}
signed main(){
	freopen("army.in","r",stdin);
	freopen("army.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>m>>mod;
	for(int i=1;i<=n;i++) cin>>a[i];	
	fac[0]=1;
	for(int i=1;i<=19;i++) fac[i]=fac[i-1]*i;
	for(int i=20;i<=n;i++) fac[i]=2e18;
	int ans=0;
	for(int i=n,lst=1,chu,len;i;i--){
		chu=query(a[i]);
		if(lst>m){
			(ans+=m%mod*chu)%=mod;
			goto togo;
		}
		(ans+=(lst-1)%mod*chu)%=mod;//在下一个循环节之前,这是一个不满的块,计算这部分的贡献 
		if(lst>1) chu++;//存在下一个循环,跳到下一个值 
		for(;chu<=n-i;chu++){//处理跳到整循环之前的若干个散块的值 
			if(lst+fac[n-i]-1>m){//如果下一个块不完整(也就是跳到一部分就结束了),那么特殊处理 
				(ans+=(m-lst+1)%mod*chu)%=mod;
				lst=2e18;
				goto togo;
			}
			(ans+=fac[n-i]%mod*chu)%=mod;//否则贡献增加块长和值的积 
			lst+=fac[n-i];//距离下一个循环节开始是现在的开始位置增加块长 
		}
		(ans+=(m-lst+1)/fac[n-i+1]%mod*(fac[n-i]%mod)%mod*((n-i+1)*(n-i)/2%mod))%=mod;//对于整循环块,直接用等差数列求解 
		len=(m-lst+1)%fac[n-i+1];//跳到整循环块结束位置,处理距离末尾之间的散块 
		for(int j=0;;j++){
			if(len<fac[n-i]){//不足一个散块 
				(ans+=len%mod*j)%=mod;
				break; 
			}
			(ans+=fac[n-i]%mod*j)%=mod;//处理满的散块 
			len-=fac[n-i];
		}
		togo:;
		add(a[i],1);//在树状数组中插入当前值 
	}
	cout<<ans;
	return 0;
}

T4 终末螺旋

什么?真的吗?你知道吗?我真的能够改出T4吗?

奋战一天,我真改出了T4,也是第一次改出S组T4,值得纪念;

我们将颜色 \(i\) 的两座塔视为一个区间 \([l_i,r_i]\) ,每次点亮一个区间,所有与这个区间有包含或相交关系的区间也会被点亮,直到最后无法拓展,这样就把整个数列分成了若干段,那么显然,对于第一个答案,就是上述无法拓展的区间的数量;

考虑如何计算这个东西,因为满足区间内的颜色均出现了两次,我们可以用异或前缀和判断,对于两个异或前缀和为零的位置,其中间就是一个无法拓展的根区间,那么我们记录前缀和为0的位置即可(记录时要把第0个位置加入,但是在计算答案时不统计位置0的贡献)

在一个根区间中,如果两个位置的前缀和记为 \(qzh_i,qzh_j\) 相同,就代表在 \([i+1,j]\) 这段区间内出现的所有颜色都出现过两次,也就是整个区间构成包含关系,对于区间内任意点 \(x(i+1 \leq x \leq j)\) 选择这个点后无法拓展超过这个区间,那么一定不优;

对于最后的答案,我们我们枚举每一个根区间,查询其中未被覆盖的点的数量,计算每个根区间部分的乘积即可;

以上时间复杂度,暴力维护是 \(O(nq)\) 的,如果用vector维护可以取得40分,但是如果用set,因为常熟过大只有25分,不过正解仍然要使用set;

不过还是放上40分代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=8e5+10;
const int INF=1e18+7;
const int mod=998244353;
int seed=1;int rand1(){return seed*=20100603;} 
int n,q,a[MAXN],l[MAXN],r[MAXN],cnt,ans;
int qzh[MAXN],val[MAXN];
vector<int> e;
unordered_map<int,int> mp;
struct tree{
	int l,r,sum,minn,minn_sum;
	int lazy;
}tr[MAXN<<2];
#define lc id<<1
#define rc id<<1|1
void pushup(int id){
	tr[id].sum=tr[lc].sum+tr[rc].sum;
	return ;
}
void pushdown(int id){
	if(tr[id].lazy){
		tr[lc].sum=0;
		tr[rc].sum=0;
		tr[lc].lazy=tr[rc].lazy=1;
		tr[id].lazy=0;
	}
	return ;
}
void build(int id,int l,int r){
	tr[id].l=l,tr[id].r=r,tr[id].minn=tr[id].lazy=0;
	if(l==r){
		tr[id].sum=1;
		return ;
	}
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	pushup(id);
	return ; 
}
void add(int id,int l,int r,int val){
	if(l>r) return ;
	if(l<=tr[id].l&&tr[id].r<=r){
		tr[id].lazy=1;
		tr[id].sum=0;
		tr[id].minn+=val;
		return ; 
	}
	pushdown(id);
	int mid=tr[id].l+tr[id].r>>1;
	if(l<=mid) add(lc,l,r,val);
	if(r>mid) add(rc,l,r,val);
	pushup(id);
	return ;
}
int query(int id,int l,int r){
	if(l>r) return 0;
	if(l<=tr[id].l&&tr[id].r<=r){
		return tr[id].sum;
	}
	pushdown(id);
	int ans=0,mid=tr[id].l+tr[id].r>>1;
	if(l<=mid) ans+=query(lc,l,r);
	if(r>mid) ans+=query(rc,l,r);
	return ans;
}
struct fio{
	#define isdigit(x) (x >= '0' && x <= '9')
	char buf[1 << 20], *p1, pbuf[1 << 20], *p2, *pp;
	fio() : p1(buf), p2(buf), pp(pbuf){}
	~fio(){fwrite(pbuf, 1, pp - pbuf, stdout);}
	inline char gc(){return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1 ++;}
	inline void pc(const char &c){if (pp - pbuf == 1 << 20) fwrite(pbuf, 1, 1 << 20, stdout), pp = pbuf;*pp ++ = c;}
	inline bool blank(char ch){return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';}
	template <class T> inline void read(T &x){
		long double tmp = 1;bool sign = 0;char ch = gc();x = 0;
		for (;!isdigit(ch);ch = gc()) if (ch == '-') sign = 1;
		for (;isdigit(ch);ch = gc()) x = x * 10 + (ch - '0');
		if (ch == '.') for (ch = gc();isdigit(ch);ch = gc()) tmp /= 10.0, x += tmp * (ch - '0');
		if (sign) x = -x;
	}
	inline void read(char *s){
    	char ch = gc();for (;blank(ch);ch = gc());
    	for (;!blank(ch);ch = gc()) *s ++ = ch;*s = 0;
    }
    inline void read(char &c){for (c = gc();blank(c);c = gc());}
	template <class T> inline void write(T x){
		if (x < 0) x = -x, pc('-');int sta[30];int top = 0;
		do sta[top ++] = x % 10, x /= 10;while (x);
		while (top) pc(sta[-- top] + '0');
	}
}io;
signed main(){
	freopen("tower.in","r",stdin);
	freopen("tower.out","w",stdout);
	io.read(n);io.read(q);
	n*=2;
	for(int i=1;i<=n;i++){
		io.read(a[i]);
		if(!val[a[i]]) val[a[i]]=rand1();
		while(val[a[i]]<0) (val[a[i]]+=INF)%=INF;
		qzh[i]=qzh[i-1]^val[a[i]];
		if(qzh[i]&&!mp[qzh[i]]) mp[qzh[i]]=++cnt;
	}
	e.push_back(0);
	for(int i=1;i<=n;i++){
		if(!qzh[i])
			e.push_back(i);
		if(!l[mp[qzh[i]]]) l[mp[qzh[i]]]=i;
		r[mp[qzh[i]]]=i;
	}
	build(1,1,n);
	for(int i=1;i<=cnt;i++){
		add(1,l[i]+1,r[i],1);
	} 
	int len=e.size();
	ans=1;
	for(int i=1;i<len;i++){
		ans*=query(1,e[i-1]+1,e[i]);
		ans%=mod;
	}
	cout<<len-1<<" "<<ans<<"\n";
	for(int x=1,p;x<=q;x++){
		io.read(p);
		swap(a[p],a[p+1]);
		for(int i=1;i<=n;i++){
			qzh[i]=qzh[i-1]^val[a[i]];
			if(qzh[i]&&!mp[qzh[i]]) mp[qzh[i]]=++cnt;
		}
		e.clear();
		e.push_back(0);
		for(int i=1;i<=cnt;i++) l[i]=r[i]=0;
		for(int i=1;i<=n;i++){
			if(!qzh[i]) e.push_back(i);
			if(!l[mp[qzh[i]]]) l[mp[qzh[i]]]=i;
			r[mp[qzh[i]]]=i;
		}
		build(1,1,n);
		for(int i=1;i<=cnt;i++)
			add(1,l[i]+1,r[i],1);
		int len=e.size();ans=1;
		for(int i=1;i<len;i++){
			ans*=query(1,e[i-1]+1,e[i]);
			ans%=mod;
		}
		cout<<len-1<<" "<<ans<<"\n";
	}
	return 0;
}

考虑正解;我们发现每次交换修改的答案是十分有限的,并且发现只会影响位置 \(p\) 的前缀和值;我们记录交换前的 \(qzh_p\)\(x\) ,交换后为 \(y\) ,那么有三种情况:

1、\(x>0,y>0\) 那么只会改变当前根区间部分的答案,我们将这部分的贡献除去(这里要用逆元),并撤销 \(x,y\) 部分的修改,更新set中的元素中再把修改和贡献加回来

2、\(x=0,y>0\) 相当于把本来两个根区间合并成了一个根区间,那么将原先两个根区间的贡献除去,撤销 \(y\) 的修改,增加元素后再改回来并重新记录贡献;

3、\(x>0,y=0\) 相当于把一个大的根区间分成两个根区间,思路和2差不多,逆着操作即可;

为什么要用set:因为set自带排序,并且方便查找元素位置,除了常数大没有什么缺点;

放上代码,荣获最长解:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=1e6+10;
const int INF=1e18+7;
const int mod=998244353;
int seed=1;int rand1(){return seed*=20100603;} 
int n,q,a[MAXN],l[MAXN],r[MAXN],cnt,ans;
int qzh[MAXN],val[MAXN];
vector<int> e;
set<int> t[MAXN],_zero;
unordered_map<int,int> mp;
struct tree{
	int l,r,sum,minn,minn_sum;
	int lazy;
}tr[MAXN<<2];
#define lc id<<1
#define rc id<<1|1
void pushup(int id){
	tr[id].sum=tr[lc].sum+tr[rc].sum;
	if(tr[lc].minn==tr[rc].minn){
		tr[id].minn=tr[lc].minn;
		tr[id].minn_sum=tr[lc].minn_sum+tr[rc].minn_sum;
	}
	else if(tr[lc].minn<tr[rc].minn){
		tr[id].minn=tr[lc].minn;
		tr[id].minn_sum=tr[lc].minn_sum;
	}
	else{
		tr[id].minn=tr[rc].minn;
		tr[id].minn_sum=tr[rc].minn_sum;
	}
	return ;
}
void pushdown(int id){
	tr[id].sum=tr[lc].sum+tr[rc].sum;
	if(tr[id].lazy){
		tr[lc].sum+=tr[id].lazy*(tr[lc].r-tr[lc].l+1);
		tr[rc].sum+=tr[id].lazy*(tr[rc].r-tr[rc].l+1);
		tr[lc].minn+=tr[id].lazy,tr[rc].minn+=tr[id].lazy;
		tr[lc].lazy+=tr[id].lazy,tr[rc].lazy+=tr[id].lazy;
		tr[id].lazy=0;
	}
	return ;
}
void build(int id,int l,int r){
	tr[id].l=l,tr[id].r=r,tr[id].minn=tr[id].lazy=tr[id].sum=0;
	if(l==r){
		tr[id].minn_sum=1;
		return ;
	}
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	pushup(id);
	return ; 
}
void add(int id,int l,int r,int val){
	if(l>r) return ;
	if(l<=tr[id].l&&tr[id].r<=r){
		tr[id].lazy+=val;
		tr[id].sum+=val*(tr[id].r-tr[id].l+1);
		tr[id].minn+=val;
		return ; 
	}
	pushdown(id);
	int mid=tr[id].l+tr[id].r>>1;
	if(l<=mid) add(lc,l,r,val);
	if(r>mid) add(rc,l,r,val);
	pushup(id);
	return ;
}
int query(int id,int l,int r){
	if(l>r) return 0;
	if(l<=tr[id].l&&tr[id].r<=r){
		if(tr[id].minn==0) return tr[id].minn_sum;
		else return 0;
	}
	pushdown(id);
	int ans=0,mid=tr[id].l+tr[id].r>>1;
	if(l<=mid) ans+=query(lc,l,r);
	if(r>mid) ans+=query(rc,l,r);
	return ans;
}
struct fio{
	#define isdigit(x) (x >= '0' && x <= '9')
	char buf[1 << 20], *p1, pbuf[1 << 20], *p2, *pp;
	fio() : p1(buf), p2(buf), pp(pbuf){}
	~fio(){fwrite(pbuf, 1, pp - pbuf, stdout);}
	inline char gc(){return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1 ++;}
	inline void pc(const char &c){if (pp - pbuf == 1 << 20) fwrite(pbuf, 1, 1 << 20, stdout), pp = pbuf;*pp ++ = c;}
	inline bool blank(char ch){return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';}
	template <class T> inline void read(T &x){
		long double tmp = 1;bool sign = 0;char ch = gc();x = 0;
		for (;!isdigit(ch);ch = gc()) if (ch == '-') sign = 1;
		for (;isdigit(ch);ch = gc()) x = x * 10 + (ch - '0');
		if (ch == '.') for (ch = gc();isdigit(ch);ch = gc()) tmp /= 10.0, x += tmp * (ch - '0');
		if (sign) x = -x;
	}
	inline void read(char *s){
    	char ch = gc();for (;blank(ch);ch = gc());
    	for (;!blank(ch);ch = gc()) *s ++ = ch;*s = 0;
    }
    inline void read(char &c){for (c = gc();blank(c);c = gc());}
	template <class T> inline void write(T x){
		if (x < 0) x = -x, pc('-');int sta[30];int top = 0;
		do sta[top ++] = x % 10, x /= 10;while (x);
		while (top) pc(sta[-- top] + '0');
	}
}io;
int qpow(int a,int b){
	int res=1;
	while(b){
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
int get_inv(int x){
	return qpow(x,mod-2);
}
signed main(){
	freopen("tower.in","r",stdin);
	freopen("tower.out","w",stdout);
	io.read(n);io.read(q);
	n*=2;
	mt19937 ran(114514);
	for(int i=1;i<=n;i++){
		io.read(a[i]);
		if(!val[a[i]]) val[a[i]]=rand1();
		while(val[a[i]]<0) val[a[i]]=(val[a[i]]+INF)%INF;
		qzh[i]=qzh[i-1]^val[a[i]];
		if(qzh[i]&&!mp[qzh[i]]) mp[qzh[i]]=++cnt;
	}
	_zero.insert(0);
	for(int i=1;i<=n;i++){
		if(!qzh[i])
			_zero.insert(i);
		if(qzh[i]) t[mp[qzh[i]]].insert(i);
	}
	build(1,1,n);
	for(int i=1;i<=cnt;i++){
		add(1,(*t[i].begin())+1,*t[i].rbegin(),1);
	} 
	int len=_zero.size();
	auto bg=_zero.begin();
	ans=1;
	for(int i=1;i<len;i++){
		auto ls=bg;ls++;
		ans*=query(1,(*bg)+1,*ls);
		ans%=mod;
		bg++;
	}
	cout<<len-1<<" "<<ans<<"\n";
	for(int zch=1,p;zch<=q;zch++){
		io.read(p);
		swap(a[p],a[p+1]);
		int x=qzh[p],y=qzh[p-1]^val[a[p]];
		if(y&&!mp[y]) mp[y]=++cnt;
		qzh[p]=y;
		if(x&&y){
			auto xbf=_zero.lower_bound(p);xbf--;
			auto xbs=_zero.lower_bound(p);
			ans=ans*get_inv(query(1,(*xbf)+1,*xbs))%mod;
			if(t[mp[x]].size()) add(1,(*t[mp[x]].begin())+1,*t[mp[x]].rbegin(),-1);
			if(t[mp[y]].size()) add(1,(*t[mp[y]].begin())+1,*t[mp[y]].rbegin(),-1);
			t[mp[x]].erase(p);t[mp[y]].insert(p);
			if(t[mp[x]].size()) add(1,(*t[mp[x]].begin())+1,*t[mp[x]].rbegin(),1);
			if(t[mp[y]].size()) add(1,(*t[mp[y]].begin())+1,*t[mp[y]].rbegin(),1);
			ans=ans*query(1,(*xbf)+1,*xbs)%mod;
			ans%=mod;
		}
		else if(!x&&y){
			auto xbs=_zero.lower_bound(p);
			auto xbf=xbs;xbf--;
			auto xbc=xbs;xbc++;
			ans=ans*get_inv(query(1,(*xbf)+1,*xbs))%mod;
			ans=ans*get_inv(query(1,(*xbs)+1,*xbc))%mod;
			if(qzh[p]&&!mp[qzh[p]]) mp[qzh[p]]=++cnt;
			if(t[mp[y]].size()) add(1,(*t[mp[y]].begin())+1,*t[mp[y]].rbegin(),-1);
			t[mp[y]].insert(p);_zero.erase(p);
			add(1,(*t[mp[y]].begin())+1,*t[mp[y]].rbegin(),1);
			xbs=_zero.lower_bound(p);
			xbf=xbs;xbf--;
			ans=ans*query(1,(*xbf)+1,*xbs);
			ans%=mod;
		}
		else if(x&&!y){
			auto xbs=_zero.lower_bound(p);
			auto xbf=xbs;xbf--;
			ans=ans*get_inv(query(1,(*xbf)+1,*xbs))%mod;
			add(1,(*t[mp[x]].begin())+1,*t[mp[x]].rbegin(),-1);
			t[mp[x]].erase(p);_zero.insert(p); 
			if(t[mp[x]].size()) add(1,(*t[mp[x]].begin())+1,*t[mp[x]].rbegin(),1);
			ans=ans*query(1,(*xbf)+1,p)%mod;
			ans=ans*query(1,p+1,*xbs)%mod;
			ans%=mod;
		} 
		cout<<_zero.size()-1<<" "<<ans<<"\n";
	}
	return 0;
}
posted @ 2025-08-16 21:22  zhangch_qwq  阅读(14)  评论(0)    收藏  举报