2021.10.18考试总结[NOIP模拟76]

T1 洛希极限

不难发现每个点肯定是被它上一行或上一列的点转移。可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化。

预处理稍显ex。可以用并查集维护一个链表,记录当前点之后第一个没有被预处理的点的位置,这样就保证了每个点只会被更新一次。

同时正因为只被更新一次,所以行列的预处理都应先排序。

单调队列可以手写结构体,维护方案数比较方便。

\(code:\)

T1
#include<bits/stdc++.h>
using namespace std;
#define int long long

namespace IO{
	typedef long long LL;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	};
	auto write=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=2010,mod=1e9+7;
int T,n,m,q,lft[NN][NN],dwn[NN][NN];
int f[NN][NN],g[NN][NN],nxt[NN][NN];
int mx,sm;
struct matrix{
	int r1,r2,c1,c2;
}t[500010];

struct QUEUE{
	int pos,head,tail,cnt,q[NN];
	bool type;
	void check_head(){
		if(head==tail){ cnt=0; return; }
		if(type){
			if(f[q[head]][pos]==f[q[head+1]][pos]) (cnt+=mod-g[q[head]][pos])%=mod;
			else{
				cnt=0;
				for(int i=head+1;f[q[i]][pos]==f[q[head+1]][pos]&&i<=tail;++i) (cnt+=g[q[i]][pos])%=mod;
			}
		} else{
			if(f[pos][q[head]]==f[pos][q[head+1]]) (cnt+=mod-g[pos][q[head]])%=mod;
			else{
				cnt=0;
				for(int i=head+1;f[pos][q[i]]==f[pos][q[head+1]]&&i<=tail;++i) (cnt+=g[pos][q[i]])%=mod;
			}
		}
	}
	void check_tail(int a){
		if(type) (cnt+=mod+g[q[tail]][pos]*(f[q[tail]][pos]==f[q[head]][pos])*a)%=mod;
		else (cnt+=mod+g[pos][q[tail]]*(f[pos][q[tail]]==f[pos][q[head]])*a)%=mod;
	}
	void poph(){ check_head(); ++head; }
	void popt(){ check_tail(-1); --tail; }
	void clear(){ head=1; tail=cnt=0; }
	void push(int a){ q[++tail]=a; check_tail(1); }
	bool empty(){ return head>tail; }
	int front(){ return head>tail?0:q[head]; }
	int back(){ return head>tail?0:q[tail]; }
	int sum(){ return cnt; }
}r[NN],c[NN];

int getx(int x,int y){ return nxt[x][y]==x?x:nxt[x][y]=getx(nxt[x][y],y); }
int gety(int x,int y){ return nxt[x][y]==y?y:nxt[x][y]=gety(x,nxt[x][y]); }
void init(){
	mx=sm=0;
	for(int i=1;i<=n;i++) r[i].clear();
	for(int i=1;i<=m;i++) c[i].clear();
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
		lft[i][j]=dwn[i][j]=2e9,f[i][j]=g[i][j]=0;
	sort(t+1,t+q+1,[](matrix a,matrix b)->bool{ return a.r1<b.r1; });
	for(int i=1;i<=n+1;i++) for(int j=1;j<=m+1;j++) nxt[i][j]=i;
	for(int i=1;i<=q;i++)
		for(int j=t[i].c1+1;j<=t[i].c2;j++)
			for(int k=getx(t[i].r1+1,j);k<=t[i].r2;k=getx(k+1,j))
				lft[k][j]=t[i].r1, nxt[k][j]=getx(k+1,j);

	sort(t+1,t+q+1,[](matrix a,matrix b)->bool{ return a.c1<b.c1; });
	for(int i=1;i<=n+1;i++) for(int j=1;j<=m+1;j++) nxt[i][j]=j;
	for(int i=1;i<=q;i++)
		for(int j=t[i].r1+1;j<=t[i].r2;j++)
			for(int k=gety(j,t[i].c1+1);k<=t[i].c2;k=gety(j,k+1))
				dwn[j][k]=t[i].c1, nxt[j][k]=gety(j,k+1);
//	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)write(lft[i][j],j==m?'\n':' '); puts("");
//	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)write(dwn[i][j],j==m?'\n':' ');
}

signed main(){
	freopen("roche.in","r",stdin);
	freopen("roche.out","w",stdout);
	T=read();
	for(int i=1;i<=2000;i++)
		r[i].pos=c[i].pos=i,r[i].type=0,c[i].type=1;
	while(T--){
		n=read(); m=read(); q=read();
		for(int i=1;i<=q;i++)
			t[i].r1=read(),t[i].c1=read(),t[i].r2=read(),t[i].c2=read();
		init();
		for(int i=1;i<=n;i++) f[i][1]=g[i][1]=1;
		for(int i=1;i<=m;i++) f[1][i]=g[1][i]=1;
		for(int i=2;i<=n;i++) for(int j=2;j<=m;j++){
			while(!r[i-1].empty()&&f[i-1][r[i-1].back()]<f[i-1][j-1]) r[i-1].popt();
			r[i-1].push(j-1);
			while(!r[i-1].empty()&&r[i-1].front()<dwn[i][j]) r[i-1].poph();
			f[i][j]=f[i-1][r[i-1].front()]+1; g[i][j]=max(r[i-1].sum(),1ll);
			while(!c[j-1].empty()&&f[c[j-1].back()][j-1]<f[i-2][j-1]) c[j-1].popt();
			c[j-1].push(i-2);
			while(!c[j-1].empty()&&c[j-1].front()<lft[i][j]) c[j-1].poph();
			if(f[i][j]==f[c[j-1].front()][j-1]+1) (g[i][j]+=c[j-1].sum())%=mod;
			else if(f[i][j]<f[c[j-1].front()][j-1]+1) f[i][j]=f[c[j-1].front()][j-1]+1, g[i][j]=c[j-1].sum();
		}
//		puts("");
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
			if(mx<f[i][j]) mx=f[i][j],sm=g[i][j];
			else if(mx==f[i][j]) (sm+=g[i][j])%=mod;
//			if(f[i][j]>1)cout<<i<<' '<<j<<' '<<f[i][j]<<' '<<g[i][j]<<endl;
		}
		write(mx,' '); write(sm,'\n');
	}
	return 0;
}
/*
1
10 7 4
7 6 10 7
3 1 5 2
7 5 10 5
3 4 3 6

*/

T2 特立独行的图

分析一波发现合法的图是二分图加一个可能不存在的三元环。令值域为\([-l,l]\),那么二分图的两个部分别为正数和负数,三元环由\(0,l,-l\)组成。

找到二分图后判断两个部中的点连接的点是否构成包含关系,如果构成则可以构造。构造就一个一个加即可。

不知道为啥T了

\(code:\)

T2
#include<bits/stdc++.h>
#define nxt goto FAIL
using namespace std;

namespace IO{
	typedef long long LL;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	};
	auto write=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=1010,MM=1000010;
int T,n,m,idx,to[MM],nex[MM],head[NN],deg[NN],col[NN];
int cnt,tim,r[NN],ans[NN];
int zero,ob,ng,tot;
bool stop;
bitset<NN> S[NN];
void add(int a,int b){
	to[++idx]=b; nex[idx]=head[a]; head[a]=idx; ++deg[a]; S[a].set(b);
	to[++idx]=a; nex[idx]=head[b]; head[b]=idx; ++deg[b]; S[b].set(a);
}
void clear(){
	idx=stop=zero=ob=ng=tot=tim=cnt=0;
	for(int i=1;i<=n;i++) S[i].reset();
	memset(col,0,sizeof(col));
	memset(deg,0,sizeof(deg));
	memset(ans,0,sizeof(ans));
	memset(head,0,sizeof(head));
}

void dfs(int s,int c){
	if(stop) return;
	col[s]=c;
	for(int i=head[s];i;i=nex[i])
		if(!col[to[i]]) dfs(to[i],c^1);
		else if(col[to[i]]==col[s]) stop=1;
}

signed main(){
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	T=read();
	while(T--){
		n=read(); m=read(); clear();
		for(int i=1;i<=m;i++) add(read(),read());
		for(int i=1;i<=n;i++)
			for(int j=head[i];j;j=nex[j]) if(to[j]>i)
				for(int k=head[to[j]];k;k=nex[k]) if(to[k]>to[j]&&S[i][to[k]])
					col[i]=col[to[j]]=col[to[k]]=1;
		for(int i=1;i<=n;i++) if(col[i]){
			zero=ob; ob=ng; ng=i;
			++tot;
			if(tot>3) nxt;
		}
		if(tot){
			if(deg[ob]==2) swap(zero,ob);
			if(deg[ng]==2) swap(zero,ng);
			if(deg[zero]!=2) nxt;
			col[ng]=col[ob]=0;
		}
		for(int i=1;i<=n;i++) if(!col[i]) dfs(i,2);
		if(stop) nxt;
		for(int i=1;i<=n;i++) if(col[i]==2) r[++cnt]=i;
		if(tot){
			for(int i=head[ng];i;i=nex[i])
				if(col[to[i]]==3){ swap(ng,ob); break; }
			for(int i=head[ng];i;i=nex[i])
				if(col[to[i]]==3) nxt;
			for(int i=head[ob];i;i=nex[i])
				if(col[to[i]]==2) nxt;
			if(deg[ng]!=cnt+1||deg[ob]!=n-cnt) nxt;
			ans[ng]=-1e9;
		}
		sort(r+1,r+cnt+1,[](int a,int b)->bool{ return deg[a]<deg[b]||b==ob; });
		for(int i=1;i<cnt;i++)
			if((S[r[i]]|S[r[i+1]])!=S[r[i+1]]) nxt;
		for(int i=1;i<=cnt;i++){
			for(int j=head[r[i]];j;j=nex[j])
				if(ans[to[j]]==0) ans[to[j]]=++tim-1e9;
				ans[r[i]]=++tim;
		} ans[ob]=1e9; ans[zero]=0;
		puts("Yes");
		write(2e9,' ');
		for(int i=1;i<=n;i++) write(ans[i],i==n?'\n':' ');
		continue;
		FAIL: puts("No");
	}
	return 0;
}

T3 游戏

不会数学。

T4 骆驼

不知道怎么证明,反正在\(5\times5\)的图中总能从任意一点出发,经过所有点后到达任意一点。同时也存在从\((1,1)\)出发,不经过\((3,3)\)和从\((1,1)\)出发,不经过\((3,3),(5,5)\)的情况。

于是将矩形分割为若干个\(5\times5\)的小矩形,构造方案即可。

贴个学长题解

\(code:\)

T4
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	};
	auto write=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=1010;
const int dx[9]={0,-3,0,0,3,2,2,-2,-2};
const int dy[9]={0,0,-3,3,0,2,-2,2,-2};
int n,m,t,endt,tim[6][6],ans[NN][NN];
int st[6][6],dn[6][6],up[6][6],lf[6][6],rt[6][6],ed[6][6];
bool stop;

void dfs(int x,int y,int endx,int endy,int lmtx,int lmty,int t){
	if(stop) return;
	tim[x][y]=t;
	if(t==endt){
		if(x!=endx||y!=endy) return tim[x][y]=0,void();
		return stop=1,void();
	}
	for(int i=1;i<=8;i++){
		int tx=x+dx[i],ty=y+dy[i];
		if(tx<=0||tx>5||ty<=0||ty>5||tim[tx][ty]) continue;
		if(tx==lmtx&&ty==lmty) continue;
		dfs(tx,ty,endx,endy,lmtx,lmty,t+1);
		if(stop) return;
	}
	tim[x][y]=0;
}

void DFS(int x,int y,int endx,int endy,int lmtx,int lmty,int t){
	if(stop) return;
	st[x][y]=t;
	if(t==endt){
		if(x!=endx||y!=endy) return st[x][y]=0,void();
		return stop=1,void();
	}
	for(int i=1;i<=8;i++){
		int tx=x+dx[i],ty=y+dy[i];
		if(tx<=0||tx>5||ty<=0||ty>5||st[tx][ty]) continue;
		if((tx==lmtx&&ty==lmty)||(tx==5&&ty==5)) continue;
		DFS(tx,ty,endx,endy,lmtx,lmty,t+1);
		if(stop) return;
	}
	st[x][y]=0;
}

void color_it(int x,int y,int tmp[6][6],int T){
	x=(x-1)*5; y=(y-1)*5;
	for(int i=1;i<6;i++)
		for(int j=1;j<6;j++)
			ans[x+i][y+j]=tmp[i][j]+T;
}

void init(){
	if(m==1){
		endt=25; dfs(1,1,3,3,0,0,1);
		for(int i=1;i<6;i++) for(int j=1;j<6;j++)
			write(tim[i][j],j==5?'\n':' ');
		exit(0);
	}
	memset(tim,0,sizeof(tim)); endt=24; t=stop=0; dfs(1,1,5,3,3,3,1); memcpy(st,tim,sizeof(tim));
	memset(tim,0,sizeof(tim)); endt=25; t=stop=0; dfs(3,3,5,3,0,0,1); memcpy(dn,tim,sizeof(tim));
	memset(tim,0,sizeof(tim)); endt=25; t=stop=0; dfs(3,3,1,3,0,0,1); memcpy(up,tim,sizeof(tim));
	memset(tim,0,sizeof(tim)); endt=25; t=stop=0; dfs(3,3,3,1,0,0,1); memcpy(lf,tim,sizeof(tim));
	memset(tim,0,sizeof(tim)); endt=25; t=stop=0; dfs(3,3,3,5,0,0,1); memcpy(rt,tim,sizeof(tim));
	memset(tim,0,sizeof(tim)); endt=25; t=stop=0; dfs(3,3,2,2,0,0,1); memcpy(ed,tim,sizeof(tim));
	if(m&1) memset(st,0,sizeof(st)),endt=23, t=stop=0, DFS(1,1,5,3,3,3,1);
	t=(m&1)?-2:-1; color_it(1,1,st,0); ans[3][3]=n*n;
	if(m&1) ans[5][5]=n*n-1;
}

signed main(){
	freopen("camel.in","r",stdin);
	freopen("camel.out","w",stdout);
	n=read(); m=n/5;
	init();
	for(int i=2;i<m;i++) color_it(i,1,dn,(t+=25));
	color_it(m,1,rt,(t+=25));
	for(int i=m;i>1;i--){
		for(int j=2;j<m;j++) color_it(i,j,rt,(t+=25));
		color_it(i,m,up,(t+=25)); --i;
		if((m&1)&&i==2) break;
		for(int j=m;j>2;j--) color_it(i,j,lf,(t+=25));
		color_it(i,2,(i==1&&!(m&1))?lf:up,(t+=25));
	}
	if(m&1){
		for(int i=m;i>2;i-=2){
			color_it(2,i,up,(t+=25));
			color_it(1,i,lf,(t+=25));
			if(i==3) break;
			color_it(1,i-1,dn,(t+=25));
			color_it(2,i-1,lf,(t+=25));
		}
		color_it(1,2,dn,(t+=25));
		color_it(2,2,ed,(t+=25));
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
		write(ans[i][j],j==n?'\n':' ');
//	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%4d",ans[i][j]);puts("");}
	return 0;
}
posted @ 2021-10-14 11:07  keen_z  阅读(87)  评论(0编辑  收藏  举报