专栏文章
题解:P4621 [COCI2012-2013#6] BAKTERIJE
P4621题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqkhc8h
- 此快照首次捕获于
- 2025/12/04 06:16 3 个月前
- 此快照最后确认于
- 2025/12/04 06:16 3 个月前
P4621 BAKTERIJE
题意略。
注意到细菌的数量相当少,因此我们逐个细菌进行考虑。对于单个细菌而言,如果将每个位置的四个朝向分别视为一个节点,那么每个节点会移动向唯一的另一个节点,那么也就构成了一个内向基环树森林。
于是,由于数据范围很小,所以如果我们希望求出到某一个点的步数,在环外的部分我们可以暴力跳,每跳一步就判断一次是否满足答案,跳到环上之后就构成一个循环。
注意到终点并不是唯一的,陷阱位置四个方向对应的节点都可以作为终点,但是可以直接 强行枚举每个细菌到达的究竟是哪个终点。然后在多个细菌的情况下,我们可以先暴力跳直到所有细菌都在环上,这样每个细菌的出现位置都构成了一个循环,然后注意到这是一个同余方程组的形式,于是可以直接使用扩展中国剩余定理求解。
一些实现上的注意事项:
- 方程组求解完后,如果步数小于跳到环上的步数,要加上若干最小公倍数直到不小于跳到环上的步数。
- 陷阱消灭细菌需要消耗一秒时间,所以最后答案还要加一。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+5;
int n,m,k,x,y,to[10][N];
char c[4]={'U','R','D','L'};
int getid(int i,int j,char c){
int ans=4*((i-1)*m+j-1);
if(c=='U')return ans+1;
else if(c=='R')return ans+2;
else if(c=='D')return ans+3;
return ans+4;
}
bool vis[10][N],flg[10][N];
int pos[N],a[10][55][55];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int siz[10][N],fa[10][N];
int find(int i,int x){
return fa[i][x]==x?x:fa[i][x]=find(i,fa[i][x]);
}
void unionn(int i,int a,int b){
int x=find(i,a),y=find(i,b);
if(x==y)return;
fa[i][x]=y;
}
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,x,y),_x=x,_y=y;
x=_y;
y=_x-(a/b)*_y;
return d;
}
int A[N],B[N];
int excrt(int n,int p){
int lcm=A[1],ans=B[1];
for(int i=2;i<=n;++i){
int x,y;
B[i]=((B[i]-ans)%A[i]+A[i])%A[i];
int d=exgcd(lcm,A[i],x,y);
if(B[i]%d)return 1e18;
x=B[i]/d*x%A[i];
A[i]/=d;
ans=ans+x*lcm;
lcm=lcm*A[i];
ans=(ans%lcm+lcm)%lcm;
}
if(ans<p)ans=(p-ans+lcm-1)/lcm*lcm+ans;
return ans;
}
int st[N];
int ed[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k>>x>>y;
for(int i=1;i<=4*n*m;++i)for(int j=1;j<=k;++j)fa[j][i]=i;
for(int i=1;i<=k;++i){
int x,y;char z;
cin>>x>>y>>z;
pos[i]=getid(x,y,z);
for(int j=1;j<=n;++j){
for(int p=1;p<=m;++p){
char c;
cin>>c;
a[i][j][p]=c-'0';
}
}
}
int tot=4*n*m;
for(int o=1;o<=k;++o){
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int p=0;p<=3;++p){
int nxt=(p+a[o][i][j])%4;
if(nxt==0&&i==1)nxt=2;
if(nxt==3&&j==1)nxt=1;
if(nxt==1&&j==m)nxt=3;
if(nxt==2&&i==n)nxt=0;
to[o][getid(i,j,c[p])]=getid(i+dx[nxt],j+dy[nxt],c[nxt]);
unionn(o,getid(i,j,c[p]),getid(i+dx[nxt],j+dy[nxt],c[nxt]));
}
}
}
}
for(int j=1;j<=k;++j){
for(int i=1;i<=tot;++i){
if(!vis[j][find(j,i)]){
int now=i;
while(!vis[j][now]){
vis[j][now]=1;
now=to[j][now];
}
if(flg[j][now])continue;
vis[j][find(j,i)]=1;
int tmp=now;
do{
flg[j][tmp]=1;
siz[j][find(j,now)]++;
tmp=to[j][tmp];
}while(tmp!=now);
}
}
}
int ans=1e18;
for(int i=0;i<(1<<2*k);++i){
int cnt=0,cnt2=0,tim=0;
for(int j=1;j<=k;++j)st[j]=pos[j];
for(int j=0;j<k;++j)ed[j+1]=(i>>(j*2)&1)*2+(i>>(j*2+1)&1);
for(int j=1;j<=k;++j)ed[j]=getid(x,y,c[ed[j]]);
for(int j=1;j<=k;++j)if(flg[j][st[j]])cnt++;
for(int j=1;j<=k;++j)if(st[j]==ed[j])cnt2++;
if(cnt2==k){
cout<<1;
return 0;
}
while(cnt!=k){
for(int j=1;j<=k;++j)if(st[j]==ed[j])cnt2--;
cnt=0;
for(int j=1;j<=k;++j)st[j]=to[j][st[j]];
for(int j=1;j<=k;++j)if(flg[j][st[j]])cnt++;
for(int j=1;j<=k;++j)if(st[j]==ed[j])cnt2++;
tim++;
if(cnt2==k)ans=min(ans,tim);
}
bool tmp=0,tmp2=0;
for(int j=1;j<=k;++j){
if(!flg[j][ed[j]])tmp=1;
if(find(j,st[j])!=find(j,ed[j]))tmp2=1;
}
if(tmp||tmp2)continue;
for(int j=1;j<=k;++j){
B[j]=tim;
A[j]=siz[j][find(j,st[j])];
int now=st[j];
while(now!=ed[j]){
now=to[j][now];
B[j]++;
}
B[j]%=A[j];
}
ans=min(ans,excrt(k,tim));
}
if(ans==1e18)ans=-2;
cout<<ans+1;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...