P4621 题解

· · 题解

拆点,将每个位置拆成从上下左右四个方向进入的情况。

原图转化为一个内向基环树。

注意到一个细菌进入陷阱有且仅有四种情况,也就是从上下左右进入,且到达时间一定可以表示成 kx+b 或 b。

剩余都是 dirty work,具体可以见代码。 总复杂度 $O(4^k\times k^2\times(\log n+\log m)+\operatorname{poly}(nm))$。 ```cpp #include <bits/stdc++.h> #define int __int128 #define add(i,j) ((i+j>=mod)?i+j-mod:i+j) using namespace std; int read(){ long long x; cin>>x; return x; } void print(int x){ cout<<(long long)x; } int n,m,k; struct node{ int mod,rem,mint; }; struct pos{ int x,y; char c; friend bool operator <(pos a,pos b){ if(a.x!=b.x) return a.x<b.x; if(a.y!=b.y) return a.y<b.y; return a.c<b.c; } }; pos go(pos a){ if(a.c=='R'&&a.y==m) a.c='L'; if(a.c=='L'&&a.y==1) a.c='R'; if(a.c=='D'&&a.x==n) a.c='U'; if(a.c=='U'&&a.x==1) a.c='D'; if(a.c=='R') a.y++; if(a.c=='L') a.y--; if(a.c=='D') a.x++; if(a.c=='U') a.x--; return a; } pair<int,int> exgcd(int a,int b){ int tag=0; if(a<b) swap(a,b),tag=1; if(b==0){ return make_pair(1,0); } auto p=exgcd(b,a%b); if(!tag) return make_pair(p.second,p.first-(a/b)*p.second); return make_pair(p.first-(a/b)*p.second,p.second); } node excrt(node a,node b){ int d=__gcd(a.mod,b.mod); if((a.rem-b.rem)%d!=0){ node ans; ans.mod=ans.rem=-1; return ans; } auto p=exgcd(a.mod/d,b.mod/d); // cout<<a.mod/d*p.first+b.mod/d*p.second<<"\n"; node ans; ans.mod=a.mod/__gcd(a.mod,b.mod)*b.mod; ans.rem=(a.rem+(b.rem-a.rem)/d*p.first*a.mod)%ans.mod; ans.mint=max(a.mint,b.mint); while(ans.rem<0) ans.rem+=ans.mod; // cout<<ans.rem%b.mod<<"\n"; return ans; } map<pos,int> mp; node a[6][5]; int top[6]; map<char,int> num; char val[4]; int g[55][55]; signed main(){ num['R']=0,num['D']=1,num['L']=2,num['U']=3; val[0]='R',val[1]='D',val[2]='L',val[3]='U'; n=read(),m=read(),k=read(); int dx=read(),dy=read(); int x[k+1],y[k+1]; char c[k+1]; for(int i=1;i<=k;i++){ x[i]=read(),y[i]=read(); cin>>c[i]; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ char t; cin>>t; g[i][j]=t-'0'; } } pos now; int cnt=0; c[i]=val[(num[c[i]]+g[x[i]][y[i]])%4]; now.x=x[i],now.y=y[i],now.c=c[i]; mp.clear(); mp[now]=cnt; now=go(now),cnt++; while(!mp[now]){ mp[now]=cnt; // cout<<cnt<<" "<<now.x<<" "<<now.y<<" "<<now.c<<"\n"; cnt++; now.c=val[(num[now.c]+g[now.x][now.y])%4]; now=go(now); // cout<<now.x<<" "<<now.y<<"\n"; } // cout<<cnt<<" "<<mp[now]<<" "; int cyc=cnt-mp[now]; // cout<<cyc<<" "; cnt=mp[now]; mp.clear(); while(!mp[now]){ mp[now]=cnt; if(now.x==dx&&now.y==dy){ a[i][++top[i]].mint=cnt; a[i][top[i]].mod=cyc; a[i][top[i]].rem=cnt%cyc; } cnt++; now.c=val[(num[now.c]+g[now.x][now.y])%4]; now=go(now); } cnt=0; now.x=x[i],now.y=y[i],now.c=c[i]; while(!mp[now]){ mp[now]=cnt; if(now.x==dx&&now.y==dy){ a[i][++top[i]].mint=cnt; a[i][top[i]].mod=-1; a[i][top[i]].rem=-1; } cnt++; now.c=val[(num[now.c]+g[now.x][now.y])%4]; now=go(now); } if(top[i]==0){ cout<<"-1"; return 0; } // cout<<top[i]<<"\n"; // for(int j=1;j<=top[i];j++){ // cout<<a[i][j].mint<<" "<<a[i][j].mod<<" "<<a[i][j].rem<<"\n"; // } } int pw=1; for(int i=1;i<=k;i++) pw*=top[i]; int minv=1e18; for(int j=0;j<pw;j++){ int cs[k+1],tmp=j; for(int i=1;i<=k;i++){ cs[i]=tmp%top[i]+1; tmp/=top[i]; } node pre; pre.mint=0,pre.mod=1,pre.rem=0; int eq=0; for(int i=1;i<=k;i++){ if(a[i][cs[i]].mod==-1){ if(a[i][cs[i]].mint==eq||eq==0){ eq=a[i][cs[i]].mint; } else{ eq=-1; break; } } else{ pre=excrt(pre,a[i][cs[i]]); if(pre.mod==-1){ eq=-1; break; } } } if(eq==-1) continue; while(pre.rem<pre.mint) pre.rem+=pre.mod; if(eq==0||((eq-pre.rem>=0)&&((eq-pre.rem)%pre.mod==0))){ pre.rem=max(pre.rem,eq); minv=min(minv,pre.rem); } } if(minv>1e17){ cout<<-1; } else print(minv+1); return 0; } ```