CF1335F Robots on a Grid

时间:2020-04-14
本文章向大家介绍CF1335F Robots on a Grid,主要包括CF1335F Robots on a Grid使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

比较简单的倍增
但还是看了题解才会

题意

给出一个 \(n\times m\) 的网格,每个格子有颜色,\(0\)\(1\) 白,每个格子还有一个方向,表示这个格子上的机器人会向那个方向走,并保证不会走出格子
摆放机器人,它们同时开始运动,在任意时刻不能有两个机器人在同一个格子里
先最大化机器人个数,如果多种方案机器人个数相等,再最大化摆在黑格子里的机器人数量


首先,这个路线肯定是循环的,如果不循环,就会走到无限多个格子,不合理
然后,对于任意一个格子,从那里开始走到完成一个完整的循环,步数肯定小于等于 \(nm\),显然它不能走了比 \(nm\) 还多的格子仍然不开始循环
而对于两个不同的循环,它们一定没有交点(就是一个相同的格子),如果有,肯定就不会行成两个循环了

如果有两个机器人分别走了至少 \(nm\) 步,那么它们肯定已经各子循环了一次或以上了
所以,如果它们不在同一个循环,显然不会相遇
如果在一个循环,且没有在 \(nm\) 步内相遇,说明这时它们已经“同步”了,就是会一直保持这一个距离不断的走,永不相遇
当然,如果在 \(nm\) 步之前就已经相遇,那么它们会一直一起走,不会有影响

至此,我们判断两个格子上的机器人是否会相遇的方法,就是看它们走了 \(nm\) 步以后,是不是在同一个格子

所以,假设我们在所有格子都摆上机器人,让他们走,一旦有几个相遇了,就说明我们要去掉这些机器人只剩下其中的一个
这时,给这 \(nm\) 个点编号 \(1\ldots nm\),并用\(white_i,black_i\)表示的分别是有没有从白/黑格出发的机器人,\(nm\) 格后会走到这里

然后从 \(1\)\(nm\) 统计答案,如果某个格子可以由黑色格子中的机器人走来,就保留黑色格子的那个,否则任意保留
就可以计算出答案了

对于走 \(nm\) 步那个操作,就要用倍增实现

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int black[1000006],white[1000005];
int nex[24][1000006];
int color[1000006];
char s[1000006];
int main(){int T=read();while(T--){
	int n=read(),m=read();
	for(reg int i=1;i<=n;i++){
		std::scanf("%s",s+1);
		for(reg int j=1;j<=m;j++) color[(i-1)*m+j]=s[j]=='0'?0:1;
	}
	for(reg int i=1;i<=n;i++){
		std::scanf("%s",s+1);
		for(reg int j=1;j<=m;j++){
			int now=(i-1)*m+j;
			if(s[j]=='U') nex[0][now]=now-m;
			else if(s[j]=='D') nex[0][now]=now+m;
			else if(s[j]=='L') nex[0][now]=now-1;
			else nex[0][now]=now+1;
		}
	}
	n*=m;
	for(reg int i=1;i<=20;i++)
		for(reg int j=1;j<=n;j++) nex[i][j]=nex[i-1][nex[i-1][j]];
	for(reg int j=1;j<=n;j++){
		int to=j;
		for(reg int i=20;~i;i--){//倒着循环,倍增传统套路,不过想想也能知道,要先走大的步数 
			if((1<<i)&n) to=nex[i][to];
		}
		color[j]?white[to]=1:black[to]=1;
	}
	int ans=0,black_num=0;
	for(reg int i=1;i<=n;i++)
		if(black[i]) black_num++,ans++,black[i]=white[i]=0;
		else if(white[i]) ans++,black[i]=white[i]=0;
	std::printf("%d %d\n",ans,black_num);
}
	return 0;
}

原文地址:https://www.cnblogs.com/suxxsfe/p/12699630.html