P4621 [COCI2012-2013#6] BAKTERIJE 题解

P4621 [COCI2012-2013#6] BAKTERIJE 题解


知识点

扩展中国剩余定理。


题意分析

给你 \(K\) 个网格图及其起点坐标和方向,求 \(K\) 个网格图上的点同时到达给定终点 \((X,Y)\) 的最小时间。


思路分析

首先,显而易见的是每个点得拆成四个方向的分点,而每个方向只有一个出边,这就容易让人想到内向基环树。但是,这题的起点是固定的,那么我们最多只需维护一条基环树下的链,所以一遍 DFS 或迭代就可以搞定链长和环长。

那么最后的求解我们需要分别枚举 \(K\) 个网格图到达给定终点 \((X,Y)\) 时的方向,也就是它所拆成的四个点,这可以二进制枚举、DFS 或格雷码实现。

现在再考虑处理细节。假设我们现在处理的终点 \((X,Y,D)\)\(D\) 为其方向)是在以下情况:

  1. 终点 \((X,Y,D)\) 在环上:

    设环长为 \(Cyc\),从起点第一次到终点 \((X,Y,D)\) 的时间为 \(Tim\),那么我们所求的答案 \(res\) 就需要满足 \(res \equiv Tim \pmod {Cyc} \land res \ge Tim\)

  2. 终点 \((X,Y,D)\) 在链上:

    那么这张图从起点到达终点 \((X,Y,D)\) 的时间 \(Tim\) 有且仅有一种,那么我们所求的答案 \(res\) 就需要满足 \(res =Tim\)

那么最后的统计也很简单:

  • 所有枚举到的终点都在各自图的环上:

    那么题目就变成了一个线性同余方程组,注意到模数不一定互质,所以需要用扩展中国剩余定理

  • 有任意一个不在环上:

    就简单的判断一下同余就好了。

由于本题范围可以超过 long long,所以需要 __int128(不过数据没超过 long long 的范围,也可以不开)。

:本题细节很多,要谨慎编码。


CODE

时间复杂度:\(O(4^K K \log_2{A} + N M K)\)\(A\) 为求解扩展中国剩余定理时的最大数值),空间复杂度:\(O(n^2)\)

#include<bits/stdc++.h>
#define Fi first
#define Se second
#define ll long long
#define Pll pair<ll,ll>
#define INF 0x3f3f3f3f3f3f3f3f
#define tomax(a,b) ((a)=max((a),(b)))
#define tomin(a,b) ((a)=min((a),(b)))
#define FOR(i,a,b) for(int i=(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i=(a);i>=(int)(b);--i)
#define RCL(a,b,c,d) memset((a),(b),sizeof(c)*(d))
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
typedef __int128 Int;
namespace IOstream{
#define getc() getchar()
#define putc(c) putchar(c)
#define blank(c) ((c)==' '||(c)=='\n'||(c)=='\r'||(c)==(EOF))
#define isdigit(c) ('0'<=(c)&&(c)<='9')
	template<class T>inline void rd(T &x){
		static bool sign(0);
		static char ch(0);
		for(x=0,sign=0,ch=getc();!isdigit(ch);ch=getc())if(ch=='-')sign^=1;
		for(;isdigit(ch);x=(x<<1)+(x<<3)+(ch^'0'),ch=getc());
		return x=sign?-x:x,void();
	}
	template<class T>inline void wr(T x,char End='\n'){
		static short top(0),st[100];
		x<0?putc('-'),x=-x:0,top=0;
		do st[++top]=x%10,x/=10;while(x);
		for(;top;putc(st[top]^'0'),--top);
		return putc(End),void();
	}
#undef blank
#undef isdigit
}using namespace IOstream;
constexpr int N=50+10,dx[4]= {-1,0,1,0},dy[4]= {0,1,0,-1}; //U,R,D,L
//constexpr ll INF=2e20;
namespace Ex_CRT {
	ll Ex_Gcd(ll &x,ll &y,ll a,ll b) {
		if(!b)return x=1,y=0,a;
		ll G=Ex_Gcd(y,x,b,a%b);
		return y-=(a/b)*x,G;
	}
	bool merge(Pll &A,Pll B) {
		A.Fi%=A.Se,B.Fi%=B.Se;
		ll x=0,y=0,a=A.Se,b=B.Se,c=B.Fi-A.Fi,g=Ex_Gcd(x,y,a,b);
		if(c%g)return 0;
		return x*=c/g,x=(x%(b/g)+(b/g))%(b/g),A=(Pll) {a*x+A.Fi,a/g*b},1;
	}
	Pll CRT(const vector<Pll> &vec) {
		Pll res= {0,1};
		for(const Pll &x:vec)if(!merge(res,x))return (Pll) {
				INF,INF
			};
		return res;
	}
}
int n,m,Q,X,Y;
ll ans=INF;
vector<Pll> Bac[5];
namespace Bacteria {
	int turn[N][N];
	int dis[N][N][4];
	struct Place {
		int x,y,d;
		Place(int x=0,int y=0,int d=0):x(x),y(y),d(d) {}
		Place Nxt() {
			Place nxt(x,y,(d+turn[x][y])&3);
			if(x+dx[nxt.d]<1||x+dx[nxt.d]>n||y+dy[nxt.d]<1||y+dy[nxt.d]>m)nxt.d^=2;
			return nxt.x+=dx[nxt.d],nxt.y+=dy[nxt.d],nxt;
		}
	} S;
	vector<Pll> Constr() {
		char C[N];
		int Cycle;
		vector<Pll> eq;
		rd(S.x),rd(S.y),scanf("%s",C),S.d=(C[0]=='U'?0:(C[0]=='R'?1:(C[0]=='D'?2:3)));
		FOR(i,1,n) {
			scanf("%s",C);
			FOR(j,1,m)turn[i][j]=(C[j-1]^'0')&3;
		}
		RCL(dis,-1,dis,1),dis[S.x][S.y][S.d]=1;
		for(Place u=S,v=u.Nxt();; u=v,v=u.Nxt()) {
			if(~dis[v.x][v.y][v.d]&&(S=v,Cycle=dis[u.x][u.y][u.d]-dis[v.x][v.y][v.d]+1,1))break;
			dis[v.x][v.y][v.d]=dis[u.x][u.y][u.d]+1;
		}
		FOR(d,0,3)if(~dis[X][Y][d])eq.push_back({dis[X][Y][d],dis[X][Y][d]<dis[S.x][S.y][S.d]?-1:Cycle});
		return eq;
	}
}
void dfs(int u,vector<Pll> &cur) {
	if(u>=Q) {
		ll t=-1;
		for(const Pll &x:cur)if(!~x.Se&&(t=x.Fi,1))break;
		if(~t) {
			bool flag=1;
			for(const Pll &x:cur)flag&=(!~x.Se?x.Fi==t:t>=x.Fi&&t%x.Se==x.Fi%x.Se);
			if(flag)tomin(ans,t);
			return;
		}
		Pll res=Ex_CRT::CRT(cur);
		if(res.Fi>=INF&&res.Se>=INF)return;
		t=res.Fi;
		for(const Pll &x:cur)if(x.Fi>res.Fi)tomax(t,res.Fi+(x.Fi-res.Fi-1+res.Se)/res.Se*res.Se);
		return tomin(ans,t),void();
	}
	for(const Pll &x:Bac[u])cur.push_back(x),dfs(u+1,cur),cur.pop_back();
}
signed main() {
	rd(n),rd(m),rd(Q),rd(X),rd(Y);
	FOR(i,0,Q-1)Bac[i]=Bacteria::Constr();
	vector<Pll> cur;
	dfs(0,cur),wr(ans>=INF?-1:ans,'\n');
	return 0;
}

posted @ 2024-08-30 21:05  Add_Catalyst  阅读(14)  评论(0)    收藏  举报