省选测试14

总结

省选测试14

省选测试14

前面三位 \(AK\) 大佬

这一套题的难度确实不高,仔细想一下每一道题应该都是能做出来的

但是 \(T1\) 一个 \(lct\) 的板子调了 \(3\) 个小时实在是说不过去

后面两道题没有时间思考,只能打暴力

所以板子打熟很重要

A. 选择

分析

\(lct\) 维护双联通分量

和长跑那道题挺像的

lct学习笔记

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e6+5;
struct DSU{
	int fa[maxn];
	void init(){
		for(rg int i=1;i<maxn;i++) fa[i]=i;
	}
	int zhao(rg int xx){
		if(fa[xx]==xx) return xx;
		return fa[xx]=zhao(fa[xx]);
	}
}dsu;
struct LCT{
	int rev[maxn],ch[maxn][2],fa[maxn],sta[maxn],tp;
	void push_down(rg int da){
		if(rev[da]==0) return;
		rg int lc=ch[da][0],rc=ch[da][1];
		rev[lc]^=1,rev[rc]^=1,rev[da]^=1;
		std::swap(ch[da][0],ch[da][1]);
	}
	bool isroot(rg int da){
		return ch[fa[da]][0]!=da&&ch[fa[da]][1]!=da;
	}
	void xuanzh(rg int x){
		rg int y=fa[x];
		rg int z=fa[y];
		rg int k=(ch[y][1]==x);
		if(!isroot(y)) ch[z][ch[z][1]==y]=x;
		fa[x]=z;
		ch[y][k]=ch[x][k^1];
		fa[ch[x][k^1]]=y;
		ch[x][k^1]=y;
		fa[y]=x;
	}
	void splay(rg int x){
		sta[tp=1]=x;
		for(rg int i=x;!isroot(i);i=fa[i]) sta[++tp]=fa[i];
		for(rg int i=tp;i>=1;i--) push_down(sta[i]);
		while(!isroot(x)){
			rg int y=fa[x];
			rg int z=fa[y];
			if(!isroot(y)){
				(ch[y][1]==x)^(ch[z][1]==y)?xuanzh(x):xuanzh(y);
			}
			xuanzh(x);
		}
	}
	void access(rg int x){
		for(rg int y=0;x;y=x,x=dsu.zhao(fa[x])){
			splay(x);
			ch[x][1]=y;
			fa[y]=x;
		}
	}
	void makeroot(rg int x){
		access(x);
		splay(x);
		rev[x]^=1;
		push_down(x);
	}
	int findroot(rg int x){
		access(x);
		splay(x);
		push_down(x);
		while(ch[x][0]){
			x=ch[x][0];
			push_down(x);
		}
		splay(x);
		return x;
	}
	void split(rg int x,rg int y){
		makeroot(x);
		access(y);
		splay(y);
	}
	void link(rg int x,rg int y){
		makeroot(x);
		fa[x]=y;
	}
	void dfs(rg int now,rg int rt){
		dsu.fa[now]=rt;
		if(ch[now][0]) dfs(ch[now][0],rt);
		if(ch[now][1]) dfs(ch[now][1],rt);
	}
	void ad(rg int x,rg int y){
		x=dsu.zhao(x),y=dsu.zhao(y);
		if(x==y) return;
		if(findroot(x)!=findroot(y)){
			link(x,y);
		} else {
			split(x,y);
			dfs(y,y);
		}
	}
}lct;
int n,m,q,x[maxn],y[maxn];
int op[maxn],op1[maxn],op2[maxn],jud[maxn],ans[maxn];
std::map<std::pair<int,int>,int> mp;
int main(){
	n=read(),m=read(),q=read();
	for(rg int i=1;i<=m;i++){
		x[i]=read(),y[i]=read();
		if(x[i]>y[i]) std::swap(x[i],y[i]);
		mp[std::make_pair(x[i],y[i])]=i;
	}
	rg char ch;
	for(rg int i=1;i<=q;i++){
		scanf(" %c",&ch);
		op1[i]=read(),op2[i]=read();
		if(op1[i]>op2[i]) std::swap(op1[i],op2[i]);
		if(ch=='Z'){
			op[i]=1;
			jud[mp[std::make_pair(op1[i],op2[i])]]=1;
			op1[i]=mp[std::make_pair(op1[i],op2[i])];
		} else {
			op[i]=2;
		}
	}
	dsu.init();
	for(rg int i=1;i<=m;i++){
		if(!jud[i]){
			lct.ad(x[i],y[i]);
		}
	}
	for(rg int i=q;i>=1;i--){
		if(op[i]==1){
			lct.ad(x[op1[i]],y[op1[i]]);
		} else {
			if(dsu.zhao(op1[i])==dsu.zhao(op2[i])) ans[i]=1;
		}
	}
	for(rg int i=1;i<=q;i++){
		if(op[i]==2){
			if(ans[i]) printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}

B. 三元组

分析

省选测试14

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=2e6+5,mod=1e9+7;
inline int addmod(rg int now1,rg int now2){
	return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
	return now1*=now2,now1>=mod?now1%mod:now1;
}
int t,n,ans,suml[maxn],sumr[maxn],m,cfl1[maxn],cfl2[maxn],cfr1[maxn],cfr2[maxn],f[maxn];
char s1[maxn],s[maxn];
void adl(rg int l,rg int r,rg int a0,rg int d){
	cfl1[l+1]=addmod(cfl1[l+1],d);
	cfl1[r+1]=addmod(cfl1[r+1],mod-d);
	cfl2[l]=addmod(cfl2[l],a0);
	cfl2[r+1]=addmod(cfl2[r+1],mod-a0);
	cfl2[r+1]=addmod(cfl2[r+1],mod-mulmod(r-l,d));
}
void adr(rg int l,rg int r,rg int a0,rg int d){
	cfr1[l+1]=addmod(cfr1[l+1],d);
	cfr1[r+1]=addmod(cfr1[r+1],mod-d);
	cfr2[l]=addmod(cfr2[l],a0);
	cfr2[r+1]=addmod(cfr2[r+1],mod-a0);
	cfr2[r+1]=addmod(cfr2[r+1],mod-mulmod(r-l,d));
}
void solve(){
	memset(suml,0,sizeof(suml));
	memset(sumr,0,sizeof(sumr));
	memset(f,0,sizeof(f));
	memset(cfl1,0,sizeof(cfl1));
	memset(cfl2,0,sizeof(cfl2));
	memset(cfr1,0,sizeof(cfr1));
	memset(cfr2,0,sizeof(cfr2));
	ans=0;
	m=n*2+1;
	s[0]='$';
	for(rg int i=1;i<=m;i++){
		if(i&1) s[i]='#';
		else s[i]=s1[i>>1];
	}
	for(rg int i=1,mids=0,r=0;i<=m;i++){
		if(i<=r) f[i]=std::min(f[2*mids-i],r-i+1);
		while(s[i+f[i]]==s[i-f[i]]) f[i]++;
		if(i+f[i]-1>r) r=i+f[i]-1,mids=i;
	}
	for(rg int i=1;i<=m;i++) f[i]--;
	for(rg int i=1;i<=m;i++){
		if(!f[i]) continue;
		if(i&1){
			adl(i/2+1,i/2+1+f[i]/2-1,i/2,mod-1);
			adr(i/2-f[i]/2+1,i/2,i/2+f[i]/2,mod-1);
		} else {
			if(f[i]>1){
				adl(i/2+1,i/2+f[i]/2,i/2-1,mod-1);
				adr(i/2-(f[i]/2),i/2-1,i/2+f[i]/2,mod-1);
			}
		}
	}
	for(rg int i=1;i<=n;i++) cfl1[i]=addmod(cfl1[i-1],cfl1[i]),cfr1[i]=addmod(cfr1[i-1],cfr1[i]);
	for(rg int i=1;i<=n;i++) cfl2[i]=addmod(cfl2[i],cfl1[i]),cfr2[i]=addmod(cfr2[i],cfr1[i]);
	for(rg int i=1;i<=n;i++) cfl2[i]=addmod(cfl2[i-1],cfl2[i]),cfr2[i]=addmod(cfr2[i-1],cfr2[i]);
	for(rg int i=1;i<=n;i++) cfl2[i]=addmod(cfl2[i],i),cfr2[i]=addmod(cfr2[i],i);
	for(rg int i=1;i<n;i++) ans=addmod(ans,mulmod(cfl2[i],cfr2[i+1]));
	printf("%d\n",ans);
}
int main(){
	t=read();
	while(t--){
		scanf("%s",s1+1);
		n=strlen(s1+1);
		solve();
	}
	return 0;
}

C. 最有价值

分析

最大权闭合子图

先把所有的贡献加起来

对于每一组 \((i,j)\) 新开一个点

由源点向这个点连收益为 \(w_{i,j}+w_{j,i}\) 的点

由这个点向 \(i\) 代表的点和 \(j\) 代表的点连无穷大的边,表示强制选

由每一个位置向它所属的数字连无穷大的边,代表强制选数字

向汇点连边权为 \(a[i]\) 的边

由每一种数字向汇点连边权为 \(b[i]-a[i]\) 的边

用总贡献减去最小割就行了

代码

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=2e4+5,maxm=105;
int h[maxn],h2[maxn],tot=2,s,t,n,m,w[maxm][maxm];
struct asd{
	int to,nxt,val;
}b[maxn*20];
void ad(rg int aa,rg int bb,rg int cc){
	b[tot].to=bb;
	b[tot].nxt=h[aa];
	b[tot].val=cc;
	h[aa]=tot++;
}
int q[maxn],head,tail,dep[maxn],mmax;
bool bfs(){
	for(rg int i=1;i<=mmax;i++){
		h[i]=h2[i];
		dep[i]=0;
	}
	q[head=tail=1]=s;
	dep[s]=1;
	while(head<=tail){
		rg int now=q[head++];
		for(rg int i=h[now];i!=-1;i=b[i].nxt){
			rg int u=b[i].to;
			if(b[i].val && !dep[u]){
				dep[u]=dep[now]+1;
				q[++tail]=u;
			}
		}
	}
	return dep[t]!=0;
}
int dfs(rg int now,rg int ac1){
	if(now==t) return ac1;
	rg int ac2=0;
	for(rg int i=h[now];i!=-1;i=b[i].nxt){
		h[now]=i;
		rg int u=b[i].to;
		if(b[i].val && dep[u]==dep[now]+1){
			rg int nans=dfs(u,std::min(b[i].val,ac1));
			b[i].val-=nans;
			b[i^1].val+=nans;
			ac1-=nans;
			ac2+=nans;
		}
		if(ac1==0) break;
	}
	if(ac2==0) dep[now]=0;
	return ac2;
}
int ans=0,T,wa[maxn],wb[maxn];
char ss[maxn];
int main(){
	T=read();
	while(T--){
		memset(h,-1,sizeof(h));
		tot=2,ans=0;
		n=read();
		scanf("%s",ss+1);
		s=1,t=2,mmax=n+2;
		for(rg int i=0;i<=9;i++) wa[i]=read(),wb[i]=read();
		for(rg int i=1;i<=n;i++){
			for(rg int j=1;j<=n;j++){
				w[i][j]=read();
				if(i!=j) ans+=w[i][j];
			}
		}
		for(rg int i=1;i<=n;i++){
			ad(i+2,ss[i]-'0'+1+mmax,0x3f3f3f3f);
			ad(ss[i]-'0'+1+mmax,i+2,0);
		}
		for(rg int i=0;i<=9;i++){
			ad(i+1+mmax,t,wb[i]-wa[i]);
			ad(t,i+1+mmax,0);
		}
		for(rg int i=1;i<=n;i++){
			ad(i+2,t,wa[ss[i]-'0']);
			ad(t,i+2,0);
		}
		mmax+=10;
		for(rg int i=1;i<=n;i++){
			for(rg int j=i+1;j<=n;j++){
				mmax++;
				ad(s,mmax,w[i][j]+w[j][i]);
				ad(mmax,s,0);
				ad(mmax,i+2,0x3f3f3f3f);
				ad(i+2,mmax,0);
				ad(mmax,j+2,0x3f3f3f3f);
				ad(j+2,mmax,0);
			}
		}
		for(rg int i=1;i<=mmax;i++) h2[i]=h[i];
		while(bfs()) ans-=dfs(s,0x3f3f3f3f);
		printf("%d\n",ans);
	}
	return 0;
}
上一篇:$Noip2013/Luogu1970$ 花匠 $dp$+思维


下一篇:省选测试13