Codeforces Round #634 (Div. 3) 比赛人数11922 慢慢的对Div. 3难度有了些感觉
[codeforces 1335F] Robots on a Grid 倍增
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1335/problem/F
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
F - Robots on a Grid | GNU C++17 | Accepted | 686 ms | 106600 KB |
思路同https://blog.csdn.net/qq_45458915/article/details/105515708?fps=1&locationNum=2
假如两个机器人会冲突的话,也就是说在某个时刻,某个格子中同时出现了两个机器人,那么在接下来的移动过程中,显然这两个机器人的路径将保持一致,我们可以先假设 n * m 个格子中初始时都有一个机器人,先让这些机器人运动 n * m 秒,甚至更多,因为 n * m 的一个矩阵,最大可以形成的一个首尾相接的环路长度就是 n * m ,所以先让所有机器人都运动 n * m 秒后,该重合的机器人都已经重合了,并且不难统计每个位置中有多少个来自黑格的机器人,此时矩阵中仍然有机器人的地方,就说明这个位置是首尾相接的环,那么ans1++,如果这个地方至少有一个来自黑格的机器人,那就说明来到这个位置的机器人初始时可以摆在黑格上,即ans2++
实现的话肯定不是暴力模拟 n * m 秒,可以利用倍增,首先将 n * m 个格子按照 0 ~ n * m - 1 编号,那么 dp[ i ][ j ] 就代表编号为 i 的点走 2^j 步可以到达的地方,这里类比于树上倍增就好,剩下的实现起来就比较简单了
倍增数据理解如下
RL
dp[0][0]=1 dp[1][0]=0
dp[0][1]=0 dp[1][1]=1
dp[0][2]=0 dp[1][2]=1
RLL
DLD
ULL
dp[0][0]=1 dp[1][0]=0 dp[2][0]=1 dp[3][0]=6 dp[4][0]=3 dp[5][0]=8 dp[6][0]=3 dp[7][0]=6 dp[8][0]=7
dp[0][1]=0 dp[1][1]=1 dp[2][1]=0 dp[3][1]=3 dp[4][1]=6 dp[5][1]=7 dp[6][1]=6 dp[7][1]=3 dp[8][1]=6
dp[0][2]=0 dp[1][2]=1 dp[2][2]=0 dp[3][2]=3 dp[4][2]=6 dp[5][2]=3 dp[6][2]=6 dp[7][2]=3 dp[8][2]=6
dp[0][3]=0 dp[1][3]=1 dp[2][3]=0 dp[3][3]=3 dp[4][3]=6 dp[5][3]=3 dp[6][3]=6 dp[7][3]=3 dp[8][3]=6
dp[0][4]=0 dp[1][4]=1 dp[2][4]=0 dp[3][4]=3 dp[4][4]=6 dp[5][4]=3 dp[6][4]=6 dp[7][4]=3 dp[8][4]=6
RRD
RLD
ULL
dp[0][0]=1 dp[1][0]=2 dp[2][0]=5 dp[3][0]=4 dp[4][0]=3 dp[5][0]=8 dp[6][0]=3 dp[7][0]=6 dp[8][0]=7
dp[0][1]=2 dp[1][1]=5 dp[2][1]=8 dp[3][1]=3 dp[4][1]=4 dp[5][1]=7 dp[6][1]=4 dp[7][1]=3 dp[8][1]=6
dp[0][2]=8 dp[1][2]=7 dp[2][2]=6 dp[3][2]=3 dp[4][2]=4 dp[5][2]=3 dp[6][2]=4 dp[7][2]=3 dp[8][2]=4
dp[0][3]=4 dp[1][3]=3 dp[2][3]=4 dp[3][3]=3 dp[4][3]=4 dp[5][3]=3 dp[6][3]=4 dp[7][3]=3 dp[8][3]=4
dp[0][4]=4 dp[1][4]=3 dp[2][4]=4 dp[3][4]=3 dp[4][4]=4 dp[5][4]=3 dp[6][4]=4 dp[7][4]=3 dp[8][4]=4
AC代码如下
#include <stdio.h>
#include <string.h>
#include <math.h>
#define maxn 1000010
int col[maxn],dir[maxn],dp[maxn][23],next[4][2]={-1,0,1,0,0,-1,0,1};//U,D,L,R
char buf[maxn];
int n,m,num[maxn][2];
int loc(int x,int y){
return x*m+y;
}
int c2i(char c){
if(c=='U')return 0;
if(c=='D')return 1;
if(c=='L')return 2;
if(c=='R')return 3;
}
int main(){
int t,i,j,limit,nm,k,ans1,ans2;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
nm=n*m,ans1=0,ans2=0;
for(i=0;i<nm;i++)num[i][0]=num[i][1]=0;//初始化
limit=log2(nm)+1;//倍增使用
for(i=0;i<n;i++){
scanf("%s",buf);
for(j=0;j<m;j++)
col[loc(i,j)]=buf[j]-'0';
}
for(i=0;i<n;i++){
scanf("%s",buf);
for(j=0;j<m;j++)
dir[loc(i,j)]=c2i(buf[j]);
}
nm=n*m;
for(i=0;i<n;i++)
for(j=0;j<m;j++){
k=dir[loc(i,j)];
dp[loc(i,j)][0]=loc(i+next[k][0],j+next[k][1]);//初始化,第2^0=1步
}
for(j=1;j<=limit;j++)//倍增
for(i=0;i<nm;i++)
dp[i][j]=dp[dp[i][j-1]][j-1];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
num[dp[loc(i,j)][limit]][col[loc(i,j)]]++;
for(i=0;i<nm;i++){
ans1+=!!(num[i][0]+num[i][1]);
ans2+=!!num[i][0];
}
printf("%d %d\n",ans1,ans2);
}
return 0;
}
弄明白了,ID之前*的意义,注意,不是指该ID是作弊者,而是指,该ID此次的提交,在比赛中AC,并且因此Out of competition.