省选模拟15

关于这次考试如此烂,就是只有暴力分,只能说是啥也不会

T1 开心消消乐

考试的时候只有\(\mathcal{O(n^2)}\)的暴力,只能过掉没问号的第一个点

发现可以由前面的数字得到关于当前球的颜色的一个函数

于是我们可以线性判断一个序列是否合法,然后考虑在这个基础上dp

然而我们一般想的是直接把判断是否合法变成当前状态的方案数就行了

但是写着写着就发现,好像方案数记的不是序列个数,而是序列个数乘上操作的方案数

我们开始考虑如何去掉操作的方案数,然后失败了......

但是我们发现,一个序列会对应好多的合法方案,但是在你判断是否合法的那个状态中只对应了一个状态

所以我们将判断是否合法的那个状态全部压缩到dp中,也就是dp套dp

这样的话,一个序列只会唯一对应一个状态

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 mod=998244353;
void mo(int &x){if(x>=mod)x-=mod;}
const int N=1e5+5;
int T,n,lim,xl[N],ans;
char ch[N];
int f[N][2][2][2][2];
int dp[2][2][2];
void sol(int i,int p,int q,int l,int r,int o,int x){
	memset(dp,0,sizeof(dp));
	dp[0][0][0]=p;dp[0][0][1]=q;dp[0][1][0]=l;dp[0][1][1]=r;
	fo(j,0,1)fo(k,0,1){
		if(!dp[0][j][k])continue;
		if(o)dp[1][lim>>((0<<2)|(x<<1)|k)&1][lim>>((1<<2)|(x<<1)|k)&1]=1;
		else dp[1][lim>>((0<<2)|(x<<1)|j)&1][lim>>((1<<2)|(x<<1)|j)&1]=1;
		int t0=lim>>((0<<2)|(x<<1)|o)&1,t1=lim>>((1<<2)|(x<<1)|o)&1;
		dp[1][t0?k:j][t1?k:j]=1;
	}
	mo(f[i+2][dp[1][0][0]][dp[1][0][1]][dp[1][1][0]][dp[1][1][1]]+=f[i][p][q][l][r]);
}
signed main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	T=read();
	while(T--){ans=0;
		scanf("%s",ch);lim=0;
		fo(i,0,7)lim|=((ch[i]-'0')<<i);
		scanf("%s",ch+1);n=strlen(ch+1);
		fo(i,1,n){
			if(ch[i]=='?')xl[i]=2;
			else xl[i]=ch[i]-'0';
		}
		for(int i=1;i<=n;i+=2)fo(j,0,1)fo(k,0,1)fo(l,0,1)fo(r,0,1)f[i][j][k][l][r]=0;
		f[1][0][1][0][0]=1;
		for(int i=2;i<=n;i+=2)fo(j,0,1)fo(k,0,1)fo(l,0,1)fo(r,0,1){
			if(!f[i-1][j][k][l][r])continue;
			fo(o,0,1){
				if(xl[i-1]!=o&&xl[i-1]!=2)continue;
				if(xl[i]==2)fo(x,0,1)sol(i-1,j,k,l,r,o,x);
				else sol(i-1,j,k,l,r,o,xl[i]);
			}
		}
		fo(j,0,1)fo(k,0,1)fo(l,0,1)fo(r,0,1){
			if(!f[n][j][k][l][r])continue;
			if((l|r)&&(xl[n]==0||xl[n]==2))ans=(ans+f[n][j][k][l][r])%mod;
			if((k|r)&&(xl[n]==1||xl[n]==2))ans=(ans+f[n][j][k][l][r])%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

T2 树上的棋局

考试的时候一直在想如何搞定整棵树的SG值,发现搞不定之后就弃掉了

其实要找的不是整棵树的SG值,而是每一个棋子的SG值,全异或起来就是整棵树的了

要找SG值的性质,发现就是到子树最深链的长度

于是我们找到树的中心,也就是直径的中点,分类讨论,用线段树树剖维护就行了

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=2e5+5;
int n,m,ans,lim;
struct E{int to,nxt;}e[N*2];
int head[N],rp;
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
int dep[N],mdp[N],mxd,tid,id,md,zd,rt;
void dfs_a(int x,int ff){
	dep[x]=dep[ff]+1;if(dep[x]>mxd)id=x,mxd=dep[x];
	for(int i=head[x];i;i=e[i].nxt){int y=e[i].to;if(y==ff)continue;dfs_a(y,x);}
}
bool ifzj[N];int f[N],g[N];
void dfs_b(int x,int ff){
	if(x==id)ifzj[x]=true;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;if(y==ff)continue;
		dfs_b(y,x);ifzj[x]|=ifzj[y];
	}if(dep[x]-1==(mxd-1)>>1&&ifzj[x])zd=x;
}
void dfs_zd(int x,int ff,int r){
	mdp[x]=dep[x]=dep[ff]+1;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;if(y==ff)continue;
		dfs_zd(y,x,r);mdp[x]=max(mdp[x],mdp[y]);
		if(x==r&&mdp[y]-1>f[zd])g[zd]=f[zd],f[zd]=mdp[y]-1;
		else if(x==r&&mdp[y]-1>g[zd])g[zd]=mdp[y]-1;
	}
}
void dfs_dp(int x,int ff){
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;if(y==ff)continue;
		f[y]=f[x]+1;g[y]=mdp[y]-dep[y];dfs_dp(y,x);
	}
}
int siz[N],son[N],top[N],fa[N];
void dfs_fi(int x,int ff){
	siz[x]=1;son[x]=0;dep[x]=dep[ff]+1;fa[x]=ff;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;if(y==ff)continue;
		dfs_fi(y,x);siz[x]+=siz[y];
		if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
	}
}
int dfn[N],dfm[N],cnt,idf[N];
void dfs_se(int x,int ff){
	top[x]=ff;dfn[x]=++cnt;idf[cnt]=x;
	if(son[x])dfs_se(son[x],ff);
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;if(y==fa[x]||y==son[x])continue;
		dfs_se(y,y);
	}dfm[x]=cnt;
}
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int eve[N*4],odd[N*4],tag[N*4];
	void pushup(int x){
		eve[x]=eve[ls]^eve[rs];
		odd[x]=odd[ls]^odd[rs];
	}
	void pushdown(int x){
		swap(eve[ls],odd[ls]);tag[ls]^=1;
		swap(eve[rs],odd[rs]);tag[rs]^=1;
		tag[x]=0;
	}
	void build(int x,int l,int r,int tp){//0f 1g
		if(l==r)return odd[x]=tp?g[idf[l]]:f[idf[l]],void();
		int mid=l+r>>1;build(ls,l,mid,tp);
		build(rs,mid+1,r,tp);pushup(x);
	}
	void ins(int x,int l,int r,int ql,int qr){
		if(ql>qr)return ;
		if(ql<=l&&r<=qr){
			swap(odd[x],eve[x]);
			tag[x]^=1;return ;
		}
		if(tag[x])pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)ins(ls,l,mid,ql,qr);
		if(qr>mid)ins(rs,mid+1,r,ql,qr);
		pushup(x);return ;
	}
	int query(int x,int l,int r,int ql,int qr){
		if(ql>qr)return 0;
		if(ql<=l&&r<=qr)return odd[x];
		if(tag[x])pushdown(x);
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret^=query(ls,l,mid,ql,qr);
		if(qr>mid)ret^=query(rs,mid+1,r,ql,qr);
		pushup(x);return ret;
	}
	#undef ls
	#undef rs
}xdsf,xdsg;
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}return dep[x]<dep[y]?x:y;
}
void ins(int x,int y){
	int lca=LCA(x,y),ret=0;
	while(top[x]!=top[lca]){
		xdsf.ins(1,1,n,dfn[top[x]],dfn[x]);
		xdsg.ins(1,1,n,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	xdsf.ins(1,1,n,dfn[lca],dfn[x]);
	xdsg.ins(1,1,n,dfn[lca],dfn[x]);
	while(top[y]!=top[lca]){
		xdsf.ins(1,1,n,dfn[top[y]],dfn[y]);
		xdsg.ins(1,1,n,dfn[top[y]],dfn[y]);
		y=fa[top[y]];
	}
	xdsf.ins(1,1,n,dfn[lca]+1,dfn[y]);
	xdsg.ins(1,1,n,dfn[lca]+1,dfn[y]);
}
int query(int x,int y){
	int lca=LCA(x,y),ret=0;
	while(top[x]!=top[lca]){
		ret^=xdsf.query(1,1,n,dfn[top[x]],dfn[x]);
		ret^=xdsg.query(1,1,n,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	ret^=xdsf.query(1,1,n,dfn[lca],dfn[x]);
	ret^=xdsg.query(1,1,n,dfn[lca],dfn[x]);
	while(top[y]!=top[lca]){
		ret^=xdsf.query(1,1,n,dfn[top[y]],dfn[y]);
		ret^=xdsg.query(1,1,n,dfn[top[y]],dfn[y]);
		y=fa[top[y]];
	}
	ret^=xdsf.query(1,1,n,dfn[lca]+1,dfn[y]);
	ret^=xdsg.query(1,1,n,dfn[lca]+1,dfn[y]);
	return ret;
}
void in(int l,int r){xdsf.ins(1,1,n,l,r);xdsg.ins(1,1,n,l,r);}
signed main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read();m=read();
	fo(i,1,n-1){
		int x=read(),y=read();
		add_edg(x,y);add_edg(y,x);
	}
	dfs_a(1,0);mxd=0;tid=id;dfs_a(tid,0);dfs_b(tid,0);dfs_zd(zd,0,zd);
	for(int i=head[zd];i;i=e[i].nxt){
		int y=e[i].to;
		if(mdp[y]==mdp[zd])f[y]=g[zd]+1,lim=y;
		else f[y]=f[zd]+1;
		g[y]=mdp[y]-dep[y];
		dfs_dp(y,zd);
		//cout<<y<<" "<<mdp[y]<<" "<<dep[y]<<" "<<mdp[y]-dep[y]<<endl;
	}
	dfs_fi(zd,0);dfs_se(zd,zd);rt=1;
	xdsf.build(1,1,n,0);xdsg.build(1,1,n,1);
	//cout<<zd<<endl;
	//cout<<endl;
	//fo(i,1,n)cout<<i<<" "<<f[i]<<" "<<g[i]<<endl;
	//cout<<(xdsg.odd[1]^f[zd]^g[zd])<<endl;
	//cout<<zd<<endl;
	//ans=query(zd,rt);if(zd!=rt)ans^=f[zd]^g[zd];
	//cout<<ans<<" "<<xdsg.odd[1]<<endl;
	//ans^=xdsg.odd[1];printf("%d\n",ans);
	while(m--){
		int tp=read(),u,v,x;ans=0;
		if(tp==1){
			u=read();v=read();x=read();
			ins(u,v);rt=x;
		}
		else {
			u=read();x=read();int lca=LCA(u,rt);
			if(u==rt)in(1,n);
			else if(lca!=u)in(dfn[u],dfm[u]);
			else {int now=rt;
				while(top[now]!=top[u])now=fa[top[now]];
				if(now!=u)in(1,dfn[son[u]]-1),in(dfm[son[u]]+1,n);
				else {now=rt;
					while(fa[top[now]]!=u)now=fa[top[now]];
					in(1,dfn[top[now]]-1);in(dfm[top[now]]+1,n);
				}
			}rt=x;
		}
		//cout<<"ZZ"<<" "<<xdsf.query(1,1,n,dfn[2],dfn[2])<<endl;
		ans=query(zd,rt);bool fl=false;int now=rt;//cout<<now<<endl;
		while(top[now]!=top[lim]&&top[now]!=top[zd]&&dep[fa[top[now]]]>=dep[lim])now=fa[top[now]];
		if(top[now]==top[lim]&&now!=zd)fl=true;
		if(fl&&zd!=rt)ans^=xdsg.query(1,1,n,dfn[zd],dfn[zd])^xdsf.query(1,1,n,dfn[zd],dfn[zd]);
		//cout<<fl<<" "<<zd<<endl;
		//cout<<"SB"<<" "<<lim<<" "<<rt<<" "<<zd<<" "<<ans<<" "<<xdsg.odd[1]<<endl;
		ans^=xdsg.odd[1];printf("%d\n",ans);
	}
	return 0;
}

T3 社会黄油飞

有一种简单的但是不知道正确性的做法,先把所有点加入然后把度数最小的一个一个删掉,然后更新其他点的度数

正解是网络流,发现要求的其实就是一个最大权闭合子图,要选一条边就要选两个点

但是不能啥都不选,所以我们要钦定必选的点,如果每次重新跑的话,慢死啦

那就把钦定的点的流量退回去,然后再跑就行了

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=2e3+5;
const int M=6e3+5;
const int inf=0x3f3f3f3f;
int n,m,s=8e3+1,t=8e3+2,lim,ans,sum;
struct E{int to,nxt,val;}e[(M*3+N)*2];
int head[N+M],hea[N+M],rp=1;
void add_edg(int x,int y,int z){
	e[++rp].to=y;e[rp].val=z;
	e[rp].nxt=head[x];head[x]=rp;
}
int ji[N],je[N+M],dis[N+M];
bool bfs(){
	memcpy(head,hea,sizeof(hea));
	memset(dis,0x3f,sizeof(dis));
	queue<int> q;while(!q.empty())q.pop();
	q.push(s);dis[s]=0;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nxt){
			int y=e[i].to;
			if(!e[i].val||dis[y]<=dis[x]+1)continue;
			dis[y]=dis[x]+1;q.push(y);
			if(y==t)return true;
		}
	}
	return false;
}
int dfs(int x,int in){
	if(x==t)return in;
	int rest=in,go=0;
	for(int i=head[x];i;head[x]=i=e[i].nxt){
		int y=e[i].to;
		if(!e[i].val||dis[y]!=dis[x]+1)continue;
		go=dfs(y,min(e[i].val,rest));
		if(go)rest-=go,e[i].val-=go,e[i^1].val+=go;
		else dis[y]=0;
		if(!rest)break;
	}
	return in-rest;
}
void sol(int id){
	if(id-1)e[ji[id-1]].val=lim;
	if(e[ji[id]^1].val){
		for(int i=head[id];i;i=e[i].nxt){
			int y=e[i].to;
			if(y==t)continue;
			if(e[i].val){
				e[i].val--;e[i^1].val++;
				e[je[y]].val--;e[je[y]^1].val++;
			}
		}
	}
	sum-=e[ji[id]^1].val;
	e[ji[id]].val=e[ji[id]^1].val=0;
	while(bfs())sum+=dfs(s,inf);
	if(m-sum-lim>-lim)ans=true;
}
signed main(){
	freopen("socialbutterfly.in","r",stdin);
	freopen("socialbutterfly.out","w",stdout);
	n=read();m=read();lim=read();
	fo(i,1,m){
		int x=read(),y=read();
		add_edg(s,i+n,1);
		add_edg(i+n,s,0);
		je[i+n]=rp;
		add_edg(i+n,x,inf);
		add_edg(x,i+n,0);
		add_edg(i+n,y,inf);
		add_edg(y,i+n,0);
	}
	fo(i,1,n){
		add_edg(i,t,lim);
		ji[i]=rp;
		add_edg(t,i,0);
	}memcpy(hea,head,sizeof(head));
	fo(i,1,n){sol(i);if(ans)break;}
	if(ans)printf("Yes");
	else printf("No");
	return 0;
}
posted @ 2022-02-15 07:20  fengwu2005  阅读(50)  评论(0编辑  收藏  举报