题目
t(t<=5e4)组样例,每次给定一个n*m(n*m<=1e6)的格子图,
开始一个01矩阵表示(i,j)处是黑色(0)还是白色(1),
然后输入一个RLDU矩阵表示机器人处于这个位置时,下一秒会向右/左/下/上走一格,
保证边线处的字母不会使机器人越界,且保证所有的n*m之和小于等于1e6
第一问求最大的摆放机器人数,使得任意时刻两个机器人不会在同一坐标上
第二问求,在满足第一问的情况下,最多能在黑色的格子上放多少个机器人
思路来源
Codeforces群Winterzz
题解
根据相邻关系建边,发现这是一个基环内向树,大致ρ型,
即开始会在链上,走若干步就会进某个循环,并一直处于循环,
所取的答案需保证在环上每个位置只能取一个,且优先取黑色的,赛中就这么写的,100多行
赛后发现,这个可以用倍增的思想,快速幂一波,60多行
先让所有机器人走200W步,这样所有机器人都进环了
然后,将每个相同位置的机器人算入贡献1,若其中存在黑格的就算入贡献2
代码1
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define pb push_back
#define vi vector<int>
#define SZ(x) (int)(x.size())
#define sci(x) scanf("%d",&(x))
#define all(v) (v).begin(),(v).end()
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define syn ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
ll modpow(ll x,ll n,ll mod){ll res=1;for(;n;n>>=1,x=x*x%mod)if(n&1)res=res*x%mod;return res;}
const db eps=1e-8,PI=acos(-1.0);
const int N=1e6+10,M=201,INF=0x3f3f3f3f,mod=1e9+7;//998244353
int t,n,m,c,x,y,sz,now,nex,fa;
int par[N],to[N],dfn[N],tot,len,ans[N],b[N],d[N];
char col[N],dir[N],w[N];
int vis[N];
vi sm[N];
int find(int x){
return par[x]==x?x:par[x]=find(par[x]);
}
int f(int x,int y){
return x*m+y;
}
void g(int v,int &x,int &y){
x=v/m;y=v%m;
}
void unite(int x,int y){
x=find(x),y=find(y);
if(x==y)return;
if(x>y)swap(x,y);
par[y]=x;
}
void dfs(int u){
// printf("u:%d\n",u);
dfn[u]=++tot;
vis[u]=1;
if(!vis[to[u]]){
dfs(to[u]);
}
else if(vis[to[u]]==1){
len=dfn[u]-dfn[to[u]]+1;
d[to[u]]=0;
}
// printf("len:%d\n",len);
d[u]=(d[to[u]]+1)%len;
if(!ans[d[u]]){
ans[d[u]]=1;
}
if(col[u]=='0'){
ans[d[u]]=2;
}
// printf("uU:%d\n",u);
vis[u]=2;
tot--;
}
void add(int u,int v){
to[u]=v;
unite(u,v);
}
int main(){
sci(t);
while(t--){
sci(n),sci(m);sz=n*m;
rep(i,0,sz-1){
to[i]=-1;
sm[i].clear();
par[i]=i;
vis[i]=0;
}
c=0;
rep(i,0,n-1){
scanf("%s",w);
for(int j=0;w[j];j++){
col[c++]=w[j];
}
}
col[c]='\0';
c=0;
// printf("01:%s\n",col);
rep(i,0,n-1){
scanf("%s",w);
for(int j=0;w[j];j++){
dir[c++]=w[j];
}
}
dir[c]='\0';
// printf("dir:%s\n",dir);
rep(i,0,n-1){
rep(j,0,m-1){
now=f(i,j);
if(dir[now]=='U')nex=f(i-1,j);
else if(dir[now]=='R')nex=f(i,j+1);
else if(dir[now]=='D')nex=f(i+1,j);
else if(dir[now]=='L')nex=f(i,j-1);
add(now,nex);
}
}
rep(i,0,sz-1){
fa=find(i);
sm[fa].pb(i);
}
tot=0;
int all=0,blk=0;
rep(i,0,sz-1){
if(par[i]==i){
// puts("gg");
len=0;
for(auto &v:sm[i]){
// printf("v:%d\n",v);
if(!vis[v]){
dfs(v);
}
}
rep(j,0,len-1){
if(ans[j])all++;
if(ans[j]==2)blk++;
ans[j]=0;
}
}
}
printf("%d %d\n",all,blk);
}
return 0;
}
代码2
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
const int N=1e6+10;
int t,n,m,a[N],ans[N],b[N],tmp[N],nex;
int res1[N],res2[N];
char s[N],y;
int f(int x,int y){
return x*m+y;
}
void modpow(int *b,int x){
rep(i,0,n*m-1){
ans[i]=i;
}
for(;x;x>>=1){
if(x&1){
//ans=ans*b
rep(i,0,n*m-1){
tmp[i]=ans[b[i]];
}
rep(i,0,n*m-1){
ans[i]=tmp[i];
}
}
//b=b*b
rep(i,0,n*m-1){
tmp[i]=b[b[i]];
}
rep(i,0,n*m-1){
b[i]=tmp[i];
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
rep(i,0,n-1){
rep(j,0,m-1){
scanf("%1d",&a[f(i,j)]);
}
}
rep(i,0,n-1){
scanf("%s",s);
rep(j,0,m-1){
y=s[j];
if(y=='R')nex=f(i,j+1);
else if(y=='L')nex=f(i,j-1);
else if(y=='U')nex=f(i-1,j);
else if(y=='D')nex=f(i+1,j);
b[f(i,j)]=nex;
}
}
// rep(i,0,n*m-1){
// printf("%d:%d\n",i,b[i]);
// }
modpow(b,2000000);
// rep(i,0,n*m-1){
// printf("%d:%d\n",i,ans[i]);
// }
rep(i,0,n*m-1){
res1[ans[i]]=1;
if(a[i]==0)res2[ans[i]]=1;
}
int all=0,blk=0;
rep(i,0,n*m-1){
all+=(res1[i]>0);
blk+=(res2[i]>0);
res1[i]=res2[i]=0;
}
printf("%d %d\n",all,blk);
}
return 0;
}