省选模拟19

据说今天的题是老年选手出的??虽然我还搞不清啥叫老年选手...

但是总体来看今天的题并不难

第一题就是题面迷惑人,看懂了题面就行了,所以考场上我直接跳了,因为我对这种交换啊啥的有点杵头

第二题只要小小的合适变换一下就能有很大的优化,可惜了我没有看出来...

第三题有一点点思考量,并且我看上去非常的顺眼,于是乎我考场的时候先做的这一个,然而没有什么成效

就不贴排行榜了,虽然我今天考得不是很好,但是爆踩zxb......

T1 排队

就是找个最长上升子序列,然后找到所有最长上升子序列都包含的点就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=1e5+5;
const int mod=998244353;
int n,a[N],b[N];
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int mxn[N*4],sum[N*4];
	void pushup(int x){
		mxn[x]=max(mxn[ls],mxn[rs]);sum[x]=0;
		if(mxn[x]==mxn[ls])sum[x]=(sum[x]+sum[ls]+mod)%mod;
		if(mxn[x]==mxn[rs])sum[x]=(sum[x]+sum[rs]+mod)%mod;
	}
	void build(int x,int l,int r){
		if(l==r)return mxn[x]=sum[x]=0,void();
		int mid=l+r>>1;
		build(ls,l,mid);build(rs,mid+1,r);
		pushup(x);
	}
	void ins(int x,int l,int r,int pos,int v,int fas){
		if(l==r)return mxn[x]=v,sum[x]=(sum[x]+fas+mod)%mod,void();
		int mid=l+r>>1;
		if(pos<=mid)ins(ls,l,mid,pos,v,fas);
		else ins(rs,mid+1,r,pos,v,fas);
		pushup(x);
	}
	int rmx,rsm;
	void query(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr){
			if(mxn[x]<rmx||sum[x]==0)return ;
			if(mxn[x]>rmx)rmx=mxn[x],rsm=sum[x];
			else if(mxn[x]==rmx)rsm=(rsm+sum[x]+mod)%mod;
			return ;
		}
		int mid=l+r>>1;
		if(ql<=mid)query(ls,l,mid,ql,qr);
		if(qr>mid)query(rs,mid+1,r,ql,qr);
	}
	#undef ls
	#undef rs
}xds;
int f[N],g[N],ans,fro[N],beh[N],sum;
int xl[N];
bool com(int x,int y){return f[x]>f[y];}
signed main(){
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	n=read();int R=n+1;
	fo(i,1,n)a[i]=read(),b[a[i]]=i;
	xds.build(1,0,R);xds.ins(1,0,R,0,0,1);
	fo(i,1,n){
		xds.rmx=-1;xds.rsm=0;xds.query(1,0,R,0,a[i]);
		f[i]=xds.rmx+1;fro[i]=xds.rsm;
		ans=max(ans,f[i]);
		xds.ins(1,0,R,a[i],f[i],fro[i]);
	}
	fo(i,1,n)if(f[i]==ans)sum=(sum+fro[i])%mod;
	xds.build(1,0,R);xds.ins(1,0,R,R,0,1);
	fu(i,n,1){
		xds.rmx=-1;xds.rsm=0;xds.query(1,0,R,a[i],R);
		g[i]=xds.rmx+1;beh[i]=xds.rsm;
		xds.ins(1,0,R,a[i],g[i],beh[i]);
		//cerr<<g[i]<<" "<<beh[i]<<endl;
	}
	printf("%lld\n",ans);
	fo(i,1,n){
		if(f[i]+g[i]-1==ans&&fro[i]*beh[i]%mod==sum)printf("%lld ",i);
	}
	return 0;
}

T2 树论

发现式子中有一个gcd==1,于是可以合适变换然后提前

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=55;
const int M=50005;
const int mod=1e9+7;
int ksm(int x,int y){
	int ret=1;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;y>>=1;
	}return ret;
}
int n,ll[N],rr[N];
int f[N][M],ans[N],h[M];
vector<int> vec[M];
struct E{int to,nxt;}e[N*2];
int head[N],rp,R=5e4;
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
int p[M],cnt,mu[M];
bool vis[M];
void init_p(){
	mu[1]=1;fo(i,2,R){
		if(!vis[i])p[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*p[j]<=R;j++){
			vis[i*p[j]]=true;
			if(i%p[j]==0){mu[i*p[j]]=0;break;}
			else mu[i*p[j]]=-mu[i];
		}
	}
}
void dfs(int x,int ff){
	fo(i,ll[x],rr[x])f[x][i]=1;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y==ff)continue;
		dfs(y,x);
		fo(j,1,R){
			h[j]=0;for(int k=((ll[y]-1)/j+1)*j;k<=rr[y];k+=j)
				h[j]=(h[j]+f[y][k])%mod;
		}
		fo(j,ll[x],rr[x]){
			int res=0;
			for(int k:vec[j])res=(res+h[k]*mu[k]+mod)%mod;
			f[x][j]=f[x][j]*res%mod;
		}
	}
}
void dfss(int x,int ff){
	fo(i,ll[x],rr[x])ans[x]=(ans[x]+f[x][i]*i)%mod;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y==ff)continue;
		fo(j,1,R){
			h[j]=0;for(int k=((ll[y]-1)/j+1)*j;k<=rr[y];k+=j)
				h[j]=(h[j]+f[y][k])%mod;
		}
		fo(j,ll[x],rr[x]){
			int res=0;
			for(int k:vec[j])res=(res+h[k]*mu[k]+mod)%mod;
			f[x][j]=f[x][j]*ksm(res,mod-2)%mod;
		}
		fo(j,1,R){
			h[j]=0;for(int k=((ll[x]-1)/j+1)*j;k<=rr[x];k+=j)
				h[j]=(h[j]+f[x][k])%mod;
		}
		fo(j,ll[y],rr[y]){
			int res=0;
			for(int k:vec[j])res=(res+h[k]*mu[k]+mod)%mod;
			f[y][j]=f[y][j]*res%mod;
		}
		dfss(y,x);
		fo(j,1,R){
			h[j]=0;for(int k=((ll[x]-1)/j+1)*j;k<=rr[x];k+=j)
				h[j]=(h[j]+f[x][k])%mod;
		}
		fo(j,ll[y],rr[y]){
			int res=0;
			for(int k:vec[j])res=(res+h[k]*mu[k]+mod)%mod;
			f[y][j]=f[y][j]*ksm(res,mod-2)%mod;
		}
		fo(j,1,R){
			h[j]=0;for(int k=((ll[y]-1)/j+1)*j;k<=rr[y];k+=j)
				h[j]=(h[j]+f[y][k])%mod;
		}
		fo(j,ll[x],rr[x]){
			int res=0;
			for(int k:vec[j])res=(res+h[k]*mu[k]+mod)%mod;
			f[x][j]=f[x][j]*res%mod;
		}
	}
}
signed main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read();init_p();
	fo(i,1,R)for(int j=i;j<=R;j+=i)vec[j].push_back(i);
	fo(i,1,n)ll[i]=read();
	fo(i,1,n)rr[i]=read();
	fo(i,1,n-1){
		int x=read(),y=read();
		add_edg(x,y);add_edg(y,x);
	}
	dfs(1,0);dfss(1,0);
	fo(i,1,n)printf("%lld\n",ans[i]);
	return 0;
}

T3 麻烦的杂货店

第一时间想到线段树,分为两种,一个维护每个端点的信息,一个是区间分治

第二个能过,但是我考场上用的第一个,于是怎么苦思冥想都想不出来

想一下区间如何合并,合并之后贡献就是跨越区间边界的最长的合法括号序列

那么这个最长的合法括号序列一定是两个区间中的最小值中最大的那个

我们直接线段树二分找到这个边界,注意找最小值的时候还是用st表吧,常数大到过不了!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,a[N];char ch[N];
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int mnn[N*4],mrs[N*4],mls[N*4];
	void pushup(int x){
		mnn[x]=min(mnn[ls],mnn[rs]);
		if(mnn[x]==mnn[rs])mrs[x]=mrs[rs];
		else if(mnn[x]==mnn[ls])mrs[x]=mrs[ls];
		if(mnn[x]==mnn[ls])mls[x]=mls[ls];
		else if(mnn[x]==mnn[rs])mls[x]=mls[rs];
	}
	void build(int x,int l,int r){
		if(l==r)return mnn[x]=a[l],mls[x]=mrs[x]=l,void();
		int mid=l+r>>1;
		build(ls,l,mid);build(rs,mid+1,r);
		pushup(x);
	}
	int quer(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return mrs[x];
		int mid=l+r>>1,ret=-1,tmp;
		if(ql<=mid)ret=quer(ls,l,mid,ql,qr);
		if(qr>mid){
			tmp=quer(rs,mid+1,r,ql,qr);
			if(ret==-1||a[ret]>=a[tmp])ret=tmp;
		}
		return ret;
	}
	int quel(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return mls[x];
		int mid=l+r>>1,ret=-1,tmp;
		if(ql<=mid)ret=quel(ls,l,mid,ql,qr);
		if(qr>mid){
			tmp=quel(rs,mid+1,r,ql,qr);
			if(ret==-1||a[ret]>a[tmp])ret=tmp;
		}
		return ret;
	}
	int qul(int x,int l,int r,int qr,int v){
		if(mnn[x]>=v)return l;
		if(r<=qr){
			if(mnn[x]>=v)return l;
			if(l==r)return l+1;
			int mid=l+r>>1;
			if(mnn[rs]>=v)return qul(ls,l,mid,qr,v);
			else return qul(rs,mid+1,r,qr,v);
		}
		int mid=l+r>>1,ret=-1;
		if(qr>mid)ret=qul(rs,mid+1,r,qr,v);
		if((ret==-1)||ret==mid+1)ret=qul(ls,l,mid,qr,v);
		return ret;
	}
	int qur(int x,int l,int r,int ql,int v){
		if(mnn[x]>=v)return r;
		if(ql<=l){
			if(mnn[x]>=v)return r;
			if(l==r)return r-1;
			int mid=l+r>>1;
			if(mnn[ls]>=v)return qur(rs,mid+1,r,ql,v);
			else return qur(ls,l,mid,ql,v);
		}
		int mid=l+r>>1,ret=-1;
		if(ql<=mid)ret=qur(ls,l,mid,ql,v);
		if((ret==-1)||ret==mid)ret=qur(rs,mid+1,r,ql,v);
		return ret;
	}
	#undef ls
	#undef rs
}xds;
int st[N][25],lg[N],pl[N][25],pr[N][25];
int ml(int l,int r){
	int t=lg[r-l+1];
	if(a[pl[l][t]]<=a[pl[r-(1<<t)+1][t]])return pl[l][t];
	else return pl[r-(1<<t)+1][t];
}
int mr(int l,int r){
	int t=lg[r-l+1];
	if(a[pr[l][t]]<a[pr[r-(1<<t)+1][t]])return pr[l][t];
	else return pr[r-(1<<t)+1][t];
}
int merge(int l,int mid,int r){
	if(l==r)return 0;
	int pos1=ml(l-1,mid),pos2=mr(mid+1,r);
	//int pos1=xds.quel(1,0,n,l-1,mid),pos2=xds.quer(1,0,n,mid+1,r);
	//if(l==2&&mid==l+r>>1&&r==5)cerr<<"SB"<<" "<<pos1<<" "<<pos2<<" "<<a[pos2]<<" "<<a[pos2-1]<<endl;
	if(a[pos1]<a[pos2])pos1=xds.qul(1,0,n,mid,a[pos2]);
	else if(a[pos1]>a[pos2])pos2=xds.qur(1,0,n,mid+1,a[pos1]);
	return pos2-pos1;
}
int mx(int l,int r){
	int t=lg[r-l+1];
	return max(st[l][t],st[r-(1<<t)+1][t]);
}
signed main(){
	freopen("grocery.in","r",stdin);
	freopen("grocery.out","w",stdout);
	n=read();m=read();
	scanf("%s",ch+1);
	fo(i,1,n){
		if(ch[i]=='F')a[i]=a[i-1]+1;
		else a[i]=a[i-1]-1;
	}
	xds.build(1,0,n);lg[0]=-1;
	fo(i,0,n){
		st[i][0]=0;
		if(i)lg[i]=lg[i>>1]+1;
		pl[i][0]=pr[i][0]=i;
	}
	fo(j,1,19)fo(i,0,n-(1<<j)+1){
		if(i)st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
		if(i)st[i][j]=max(st[i][j],merge(i,i+(1<<j-1)-1,i+(1<<j)-1));
		if(a[pl[i][j-1]]<=a[pl[i+(1<<j-1)][j-1]])pl[i][j]=pl[i][j-1];
		else pl[i][j]=pl[i+(1<<j-1)][j-1];
		if(a[pl[i][j-1]]<a[pl[i+(1<<j-1)][j-1]])pr[i][j]=pr[i][j-1];
		else pr[i][j]=pr[i+(1<<j-1)][j-1];
	}
	while(m--){
		int l=read(),r=read();
		printf("%d\n",max(mx(l,r),merge(l,l+r>>1,r)));
	}
}
posted @ 2022-02-21 15:56  fengwu2005  阅读(34)  评论(0编辑  收藏  举报