洛谷 P4621 - [COCI2012-2013#6] BAKTERIJE(exCRT)
阿新 • • 發佈:2021-08-06
暴力列舉+exCRT 合併
形。而對於陷阱格 \((x,y)\),到達陷阱格即意味著在建好的圖上到達 \((x,y,0),(x,y,1),(x,y,2),(x,y,3)\) 中的一個點,因此題目可以轉化為:
。我們對於每個細菌 \(i\),預處理出以下四個量:
,否則繼續分類討論:如果存在一個 \((x,y,d_i)\) 不在細菌 \(i\) 的起點對應的環上,那麼顯然時間必須為 \(tim_{i,d_i}\),因為錯過這個點就無法再回來了,我們只需檢驗從所有細菌的起點開始走 \(T=tim_{i,d_i}\) 步是否能夠到達對應的終點即可,如果都能那麼就用 \(T\) 更新答案,否則不做處理。具體檢驗方法就是如果 \(typ_{i,d_i}=1\),那麼必須有 \(T\ge mn_i\) 且 \(T\equiv tim_{i,d_i}\pmod{len_i}\),否則必須有 \(tim_{i,d_i}=T\),存在 \(typ_{i,d_i}=0\) 的情況都判完了,剩餘的就是 \(typ_{i,d_i}\) 都為 \(1\) 的情況了。對於每個細菌 \(i\),顯然它在 \(T\) 時刻到達 \((x,y,d_i)\) 的充要條件是 \(T\ge mn_i\) 且 \(T\equiv tim_{i,d_i}\pmod{len_i}\)。我們如果只考慮後一個條件,那顯然就是一個解同餘方程組的問題,exCRT 合併即可,加了第一個條件,由於方程組的通解可以寫成 \(T=T_0+kT'\) 的形式,因此我們對於每個細菌求出 \(k\) 最少需要是多少才能滿足第一個限制,然後取個 \(\max\) 即可。
發篇正常點的題解。
首先對於這樣的題暴力列舉肯定是不行的,因為最小時間顯然可能達到 \((nm)^5\approx 10^{17}\),就算資料很難卡到這個上界,構造出一些使你暴力超時的資料還是很容易的,因此考慮一些不基於暴力列舉的做法。不難發現,對於每個細菌而言,如果它的位置及方向已經確定了,那麼它下一步所在的位置及面對的方向也已經確定了,也就是說,如果我們對於每個細菌,把位置及方向看作一個三元組 \((x,y,d)\),並且在一步可達的三元組之間連有向邊,那麼可以得到 \(k\) 個基環內向森林。而由於得到的圖是基環內向森林,對於一個點,從它出發可以到達的點應是一個 \(\rho\)
- 求最小的時間 \(t\),滿足對於全部全部 \(k\) 個基環內向森林的起點,走 \(t\) 步後到達的點都是 \((x,y,0),(x,y,1),(x,y,2),(x,y,3)\) 中的一個
由於此題 \(k\) 很小,因此我們考慮暴力 \(4^k\) 列舉每個細菌的終點 \((x,y,d_i)\),那麼問題可進一步轉化為,最少需要多少時間 \(t\),滿足每個細菌走 \(t\) 步後到達的點都恰好是 \((x,y,d_i)\)
- \(mn_i\):從該細菌起點對應的三元組開始,最少走多少步可以走到環上
- \(len_i\):從該細菌起點對應的三元組開始,能夠走到的 \(\rho\) 字形的環長
- \(typ_{i,d}\):對於終點 \((x,y,d)\),它在不在該細菌對應的起點能夠走到的 \(\rho\) 字形的環上
- \(tim_{i,d}\):對於終點 \((x,y,d)\),最少需要多少時間才能從細菌 \(i\) 起點對應的三元組走到 \((x,y,d)\)
那麼顯然如果存在一個 \((x,y,d_i)\) 無法從 \(i\) 的起點到達那麼就不存在這樣的 \(i\)
複雜度大概是 \(4^kk\log T+nmk\),跑得飛快,最慢的一個點只用了 6ms
const int MAXN=50;
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
int n,m,k,X,Y,id[1<<7];
int getid(int x,int y,int d){return d*n*m+(x-1)*m+y;}
pair<pii,int> getcor(int x){return mp(mp((x-1)%(n*m)/m+1,(x-1)%m+1),(x-1)/n/m);}
int a[7][MAXN+5][MAXN+5],st[7];
int getnxt(int t,int x,int y,int d){
d=(d+a[t][x][y])&3;
if(x+dx[d]<1||x+dx[d]>n||y+dy[d]<1||y+dy[d]>m)
d^=2;
return getid(x+dx[d],y+dy[d],d);
}
vector<int> rch[7];
int stk[MAXN*MAXN*4+5],tp=0,len[7];
bool vis[MAXN*MAXN*4+5];
void dfs(int t,int x){
if(vis[x]){
for(int i=1;i<=tp;i++) rch[t].pb(stk[i]);
for(int i=1;i<=tp;i++) if(stk[i]==x) len[t]=tp-i+1;
return;
} vis[x]=1;pair<pii,int> p=getcor(x);stk[++tp]=x;
dfs(t,getnxt(t,p.fi.fi,p.fi.se,p.se));
}
int need[7][5],typ[7][5];
ll gcd(ll x,ll y){return (!y)?x:gcd(y,x%y);}
void exgcd(ll x,ll y,ll &a,ll &b){
if(!y) return a=1,b=0,void();exgcd(y,x%y,a,b);
ll tmp=a;a=b;b=tmp-(x/y)*b;
}
ll smul(ll x,ll y,ll mod){
x=(x%mod+mod)%mod;y=(y%mod+mod)%mod;ll res=0;
for(;y;y>>=1,x=(x+x)%mod) if(y&1) res=(res+x)%mod;
return res;
}
pair<ll,ll> combine(ll a1,ll b1,ll a2,ll b2){
if(!~a1||!~a2) return mp(-1,-1);
ll d=gcd(a1,a2);if((b2-b1)%d) return mp(-1,-1);
ll t=(b2-b1)/d;ll k1,k2;exgcd(a1,a2,k1,k2);
k1=smul(k1,t,a2/d);ll A=a1/d*a2;
return mp(A,(smul(a1,k1,A)+b1)%A);
}
int main(){
scanf("%d%d%d%d%d",&n,&m,&k,&X,&Y);
id['U']=0;id['R']=1;id['D']=2;id['L']=3;
for(int i=1;i<=k;i++){
int x,y;char c;cin>>x>>y>>c;
st[i]=getid(x,y,id[c]);
for(int j=1;j<=n;j++) for(int l=1;l<=m;l++)
scanf("%1d",&a[i][j][l]);
}
for(int i=1;i<=k;i++){
memset(vis,0,sizeof(vis));tp=0;
dfs(i,st[i]);
// for(int x:rch[i]) printf("%d\n",x);
for(int d=0;d<4;d++){
int x=getid(X,Y,d),ps=-1;
for(int j=0;j<rch[i].size();j++) if(rch[i][j]==x) ps=j;
need[i][d]=ps;typ[i][d]=(ps>=rch[i].size()-len[i]);
// printf("%d %d %d %d %d\n",i,d,x,need[i][d],typ[i][d]);
}
} ll res=9e18;
for(int i=0;i<(1<<(k<<1));i++){
bool flg=1;
for(int j=1;j<=k;j++){
int x=i>>((j-1)<<1)&3;
if(!~need[j][x]) flg=0;
} if(!flg) continue;
int tim=-1;
for(int j=1;j<=k;j++){
int x=i>>((j-1)<<1)&3;
if(!typ[j][x]) tim=need[j][x];
}
if(~tim){
for(int j=1;j<=k;j++){
int x=i>>((j-1)<<1)&3;
if(!typ[j][x]&&need[j][x]!=tim) flg=0;
if(typ[j][x]&&(tim<rch[j].size()-len[j]||tim%len[j]!=need[j][x]%len[j]))
flg=0;
} if(flg) chkmin(res,tim);
continue;
}
pair<ll,ll> A=mp(1,0);
for(int j=1;j<=k;j++){
int x=i>>((j-1)<<1)&3;
A=combine(A.fi,A.se,len[j],need[j][x]%len[j]);
} if(!~A.fi) continue;ll tt=A.se;
for(int j=1;j<=k;j++){
int x=i>>((j-1)<<1)&3;
if(A.se<need[j][x]) chkmax(tt,A.se+(need[j][x]-A.se+A.fi-1)/A.fi*A.fi);
} chkmin(res,tt);
} printf("%lld\n",(res==9e18)?-1:(res+1));
return 0;
}