【JZOJ】6278. 跳房子

本文详细解析了一种棋盘上的跳跃问题,通过预处理和循环检测优化算法,实现了高效的move和change操作处理。文章深入探讨了如何在改变棋盘状态时,通过维护特定列的状态来避免整体状态更新带来的复杂度问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Time Limits: 4000 ms Memory Limits: 524288 KB

Input

Output

Sample Input

4 4
1 2 9 3
3 5 4 8
4 3 2 7
5 8 1 6
4
move 1
move 1
change 1 4 100
move 1

Sample Output

4 2
1 3
1 4

Data Constraint

思路

考虑没有change操作时怎么做。
对于每个位置我们都可以预处理出它跳M步后的位置。(使得棋子再度回到当前列)

在每一次move操作时,
我们直接M步M步的跳,
若其在当前列的某个位置出现两次时,则明显形成了个循环。
我们让K值对这个循环长度取模。
然后再M步M步的跳,最后再一步一步。
最坏情况复杂度是O(N+M)的,可以过。

考虑加入change操作。
一次change可能会对N*M个状态都产生影响,若同时维护每个地方跳M步后的位置,绝对会TLE。
考虑只维护一列(第一列)的状态(跳(M-1)步后落在最后一列的哪一行)。
(使得每次change更改的状态数在合理的复杂度内,均摊复杂度)
对于change一个位置的值,只对该位置前3个点的指向方向造成影响,
如果此时暴力去找有哪些第一列的点经过了该位置,又会TLE。

所以我们对于每个位置,还得维护一个值表示第一列有那些位置的点跳(M-1)步会经过它。
不难发现第一列的这些位置一定是一段连续的区间,所以我们设L,R两个数组表示它。
不过有些情况下L会大于R,即此区间是[1,R]并[L,N],这得特殊考虑一下。
L,R数组的维护,得从更改位置向后走到最后一列,
前3个点的新指向也得这样操作一次,每次走都更新一遍L,R值。

维护了L,R值,对于第一列的状态就暴力从前3个点走到最后一列更新维护其状态。

代码

打得有点丑,见谅。
这样实现细节贼恶心。

#pragma GCC optimize(3,"Ofast","inline")
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=2005;
int f[10][5]={{1,1},{0,1},{-1,1}};
int e[10][5]={{-1,-1},{0,-1},{1,-1}};
int N,M,Q,X,Y,vis[MAXN];
int a[MAXN][MAXN];
int pt[MAXN][MAXN];
int dp[MAXN][MAXN];
int L[MAXN][MAXN];
int R[MAXN][MAXN];
int vvis[10];
vector<int>P;char c[5];
queue<int>T1,T2;
inline void read(int &x){
    x=0;char c=getchar();bool f=0;
    if(c=='-')f=1;
    while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	if(f==1)x=-x;
}
int Add(int x,int y,int z){
	if(x+y>=z)return x+y-z;
	if(x+y<0)return x+y+z;
	return x+y;
}
int dfs(int x,int y){
	if(y==M-1)return dp[x][y]=x;
	int w1=(x+f[pt[x][y]][0]+N)%N;
	int w2=(y+f[pt[x][y]][1]+M)%M;
	return dp[x][y]=dfs(w1,w2);
}
inline void Init(int x,int y){
	L[x][y]=R[x][y]=-1;
	for(int i=0;i<3;i++){
		int w1=Add(x,e[i][0],N);
		int w2=Add(y,e[i][1],M);
		int ww1=Add(w1,f[pt[w1][w2]][0],N);
		int ww2=Add(w2,f[pt[w1][w2]][1],M);
		if(ww1==x&&ww2==y){
			if(L[w1][w2]==-1)continue;
			if(L[x][y]==-1){
				L[x][y]=L[w1][w2];
				R[x][y]=R[w1][w2];
				continue;
			}
			if(L[x][y]==Add(R[w1][w2],1,N))
				L[x][y]=L[w1][w2];
			else if(Add(R[x][y],1,N)==L[w1][w2])
				R[x][y]=R[w1][w2];
		}
	}
}
inline void Turn(int A,int B){
	if(B==M-1)return ;
	for(int i=0;i<3;i++){
		int x=Add(A,f[i][0],N);
		int y=Add(B,f[i][1],M);
		Init(x,y);
	}
}
inline void bfs(){
	while(!T1.empty()){
		int A=T1.front();T1.pop();
		int B=T2.front();T2.pop();
		int x=Add(A,f[pt[A][B]][0],N);
		int y=Add(B,f[pt[A][B]][1],M);
		Init(x,y);
		if(y!=M-1)T1.push(x),T2.push(y);
	}
}
int main(){
	//freopen("read.in","r",stdin);
	//freopen("output.out","w",stdout);
	freopen("jump.in","r",stdin);
	freopen("jump.out","w",stdout);
	read(N);read(M);
	for(int i=0;i<N;i++)
		for(int j=0;j<M;j++)
			read(a[i][j]);
	for(int i=0;i<N;i++)
		for(int j=0;j<M;j++){
			int rt=-1;
			for(int k=0;k<3;k++){
				int w1=Add(i,f[k][0],N);
				int w2=Add(j,f[k][1],M);
				if(rt<a[w1][w2]){
					rt=a[w1][w2];
					pt[i][j]=k;
				}
			}
		}
	memset(L,-1,sizeof(L));
	memset(R,-1,sizeof(R));
	memset(dp,-1,sizeof(dp));
	for(int i=0;i<N;i++){
		L[i][0]=R[i][0]=i;
		dp[i][0]=dfs(i,0);
	}
	for(int y=1;y<M;y++)
		for(int x=0;x<N;x++)
			Init(x,y);
	read(Q);
	while(Q--){//O(N*Q)
		scanf("%s",c+1);
		if(c[1]=='m'){
			int k;read(k);
			while(k&&Y!=0){
				int x=Add(X,f[pt[X][Y]][0],N);
				int y=Add(Y,f[pt[X][Y]][1],M);
				X=x;Y=y;k--;
			}
			if(!k){
				printf("%d %d\n",X+1,Y+1);
				continue;
			}
			memset(vis,0,sizeof(vis));
			int tot=M,Cnt=0;
			while(k>=M){
				if(vis[X]){tot=((++Cnt)-vis[X])*M;break;}vis[X]=++Cnt;
				k-=M,X=Add(dp[X][0],f[pt[dp[X][0]][M-1]][0],N);
			}
			k%=tot;
			while(k>=M)
				k-=M,X=Add(dp[X][0],f[pt[dp[X][0]][M-1]][0],N);
			while(k){
				int x=Add(X,f[pt[X][Y]][0],N);
				int y=Add(Y,f[pt[X][Y]][1],M);
				X=x;Y=y;k--;
			}
			printf("%d %d\n",X+1,Y+1);
		}
		if(c[1]=='c'){
			int A,B,V,tp[5]={0};
			read(A);read(B);read(V);
			A--;B--;a[A][B]=V;
			for(int i=0;i<3;i++){
				int x=Add(A,e[i][0],N);
				int y=Add(B,e[i][1],M);
				int rt=-1;tp[i]=pt[x][y];
				for(int j=0;j<3;j++){
					int w1=Add(x,f[j][0],N);
					int w2=Add(y,f[j][1],M);
					if(rt<a[w1][w2]){
						rt=a[w1][w2];
						pt[x][y]=j;
					}
				}
			}
			for(int i=0;i<3;i++){
				int x=Add(A,e[i][0],N);
				int y=Add(B,e[i][1],M);
				if(L[x][y]!=-1){
					dp[x][y]=dfs(x,y);
					if(R[x][y]<L[x][y]){
						for(int j=0;j<=R[x][y];j++)
							dp[j][0]=dp[x][y];
						for(int j=L[x][y];j<N;j++)
							dp[j][0]=dp[x][y];
					}
					else for(int j=L[x][y];j<=R[x][y];j++)
						dp[j][0]=dp[x][y];
				}
			}
			if(B!=0){
				while(!T1.empty())T1.pop();
				while(!T2.empty())T2.pop();
				memset(vvis,0,sizeof(vvis));			
				for(int i=0;i<3;i++){
					int x=Add(A,e[i][0],N);
					int y=Add(B,e[i][1],M);
					if(tp[i]==pt[x][y])continue;
					Turn(x,y);
					if(B!=M-1){
						if(!vvis[e[i][0]+f[tp[i]][0]+2]){
							vvis[e[i][0]+f[tp[i]][0]+2]=1;
							T1.push(Add(x,f[tp[i]][0],N));
							T2.push(Add(y,f[tp[i]][1],M));
						}
						if(!vvis[e[i][0]+f[pt[x][y]][0]+2]){
							vvis[e[i][0]+f[pt[x][y]][0]+2]=1;
							T1.push(Add(x,f[pt[x][y]][0],N));
							T2.push(Add(y,f[pt[x][y]][1],M));
						}
					}
				}
				bfs();
			}
		}
	}
}
/*
5 5
0 3 1 1 1
1 7 3 3 3
2 9 10 10 10
3 7 5 5 5
4 2 2 2 2
10000
change 3 3 0
change 3 5 0
move 4
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值