图论+倍增——cf
两种思路
找环模拟:
/* 每个格子都有看成是带一条出边的点(正反图各建一个) 那么形成的图像很多不相交的环,环上带着链 所以可以把环单独拉出来算,每个独立的环+链最多放的数量就是环的size 然后再考虑黑色格子最多 对于每个独立的环+链,给每个结点编号,定一个环上点为0,其后继是1,前驱是size-1 用这种方式把整个环+链染好色,然后[0,size-1]没种颜色的点只能有一个 */
倍增:https://www.cnblogs.com/suxxsfe/p/12699630.html
#include<bits/stdc++.h> using namespace std; #define N 2000006 int n,m,nxt[N][21],cnt[N],f[N]; char mp[N],d[N],tmp[N]; int id(int i,int j){ return (i-1)*m+j; } void init(){ for(int i=1;i<=n*m;i++)f[i]=cnt[i]=0; } int main(){ int t;cin>>t; while(t--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",tmp+1); for(int j=1;j<=m;j++) mp[id(i,j)]=tmp[j]; } for(int i=1;i<=n;i++){ scanf("%s",tmp+1); for(int j=1;j<=m;j++) d[id(i,j)]=tmp[j]; } init(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ int u,v; if(d[id(i,j)]=='L'){ u=id(i,j),v=id(i,j-1); }else if(d[id(i,j)]=='R'){ u=id(i,j),v=id(i,j+1); }else if(d[id(i,j)]=='U'){ u=id(i,j),v=id(i-1,j); }else if(d[id(i,j)]=='D'){ u=id(i,j),v=id(i+1,j); } nxt[u][0]=v; } int k=0; while((1<<(k+1))<n*m) k++; for(int i=1;i<=k;i++){ for(int j=1;j<=n*m;j++) nxt[j][i]=nxt[nxt[j][i-1]][i-1]; } //for(int i=1;i<=n*m;i++)cout<<nxt[i][0]<<" "; for(int i=1;i<=n*m;i++){ int now=n*m,u=i; for(int j=k;j>=0;j--)if(now>=(1<<j)){ now-=(1<<j); u=nxt[u][j]; } f[u]++; if(mp[i]=='0')cnt[u]++; } int sum1=0,sum2=0; for(int i=1;i<=n*m;i++){ if(f[i])sum1++; if(cnt[i])sum2++; } cout<<sum1<<" "<<sum2<<'\n'; } }