数论做题记录

#6740.费马大定理

题意

给定质数 \(p\),问 \(1\)\(L\) 中有多少个整数 \(k\),满足存在 \(x,y,z\) 使得 \(x^k+y^k \equiv z^k \pmod{p}\)

\(2\le p\le 10^7+3,1\le L\le 10^{18}\)

solution

赛时打了个表发现对于一个 \(k\) 若有解则存在 \(z=1\) 的解,于是打了 \(40\) pts 就跑路了。

挺有意思的题。

我们可以先把原根找出来,找原根可以从小到大枚举,判断对于 \(p-1\) 的每个质因子 \(x\) ,是否都有 \(g^{\frac{p-1}{x}} \not\equiv 1 \pmod{p}\),是则是一个原根,枚举的个数不会超过 \(p^{\frac{1}{4}}\)

我们发现,对于一个 \(k\)\(x^k \equiv (g^a)^k \equiv g^{ak}\),则 \(x^k\) 一定可以写成 \(g^{ak}\) 的形式,即原根的 \(k\) 的倍数次方。

我们发现,若 \(\gcd(p-1,k)\) 相同,则 \(x^k\) 可取到的值也一定相同,所以我们只需要枚举 \(p-1\) 的因子,判断其是否合法,再乘上对应的数量即可。

如何快速判断一个数 \(k\) 是否合法呢?

合法的条件是 \(x^k+y^k \equiv z^k\),即 \(g^{ak}+g^{bk} \equiv g^{ck}\),两边乘以 \(g^{ck}\) 的逆元可得 \(g^{(a-c)k}+g^{(b-c)k} \equiv 1\)

所以我们只需要找到 \(m,n\) 满足 \(g^{mk}+g^{nk} \equiv 1\)\(k\) 合法,正好和赛时打表发现的规律一致。

对于每个 \(k\),我们把 \(g^{mk}\) 标记出来,再枚举 \(n\) 判断是否合法即可,这样对于每个 \(k\) 时间复杂度是 \(O(\frac{p}{k})\) 的。

接下来我们考虑如何统计 \(\gcd(p-1,k)=d\)\(k\) 的个数。

\(L\) 以内 \(d\) 的倍数显然有 \(\left\lfloor \frac{L}{d} \right\rfloor\) 个,把是 \({kd}\ (k>1)\) 的倍数容斥掉即可。

Code
#include<cstdio>
#include<algorithm>
#include<vector>
#include<bitset>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
const int N=1e7+10;
const int inf=1e9+10;

int p;
ll L;

inline ll qpow(ll a,int b) {
	ll res=1;
	while (b) {
		if (b&1) res=res*a%p;
		a=a*a%p;b>>=1;
	}
	return res;
}

inline int get_gen(int p) {
	vector<int> tmp;
	bitset<N> vis;
	int val=p-1;
	f(i,2,val) {
		if (vis[i]) continue;
		tmp.push_back((p-1)/i);
		while (val%i==0) val/=i;
		for (int j=i+i;j<=val;j+=i) vis.set(j);
	}
	f(i,2,p) {
		int flag=1;
		for (int x:tmp) if (qpow(i,x)==1) {flag=0;break;}
		if (flag) return i;
	}
}

inline vector<int> get_d(int x) {
	vector<int> ret;
	for (int i=1;i*i<=x;i++) {
		if (x%i) continue;
		ret.push_back(i);
		if (i*i!=x) ret.push_back(x/i);
	}
	sort(ret.begin(),ret.end());
	reverse(ret.begin(),ret.end());
	return ret;
}

bitset<N> vis;
inline bool check(int gen,int d) {
	vector<ll> did;
	for (ll k=qpow(gen,d),now=k;;now=now*k%p) {
		if (vis[p+1-now]||p+1-now==now) {
			for (ll x:did) vis.reset(x);
			return 1;
		}
		if (vis[now]) break;
		vis.set(now);
		did.push_back(now);
	}
	for (ll x:did) vis.reset(x);
	return 0;
}

struct Node{int d;ll v;};
vector<Node> did;

int main() {
	freopen("fermat.in","r",stdin);
	freopen("fermat.out","w",stdout);
	scanf("%d%lld",&p,&L);
	int gen=get_gen(p);
	vector<int> D=get_d(p-1);
	ll ans=0;
	for (int d:D) {
		ll num=L/d;
		for (Node k:did) if (k.d%d==0) num-=k.v;
		did.push_back({d,num});
		ans+=check(gen,d)*num;
	}
	printf("%lld\n",ans);
	return 0;
}

[POI 2014] PAN-Solar Panels

题意

\(q\) 次询问,每次询问给定 \(a,b,c,d\),求从 \([a,b]\) 中选出一个数 \(x\)\([c,d]\) 中选出一个数 \(y\)\(\gcd(x,y)\) 的最大值是多少。

\(1\le q\le 2000,1\le a,b,c,d\le 10^9\)

solution

考虑一个数 \(g\),它的倍数在 \((l,r]\) 内出现当且仅当 \(\left\lfloor \frac{l}{g}\right\rfloor<\left\lfloor \frac{r}{g}\right\rfloor\),因为这个式子的意义是 \(r\) 以内 \(g\) 倍数个数超过 \(l\) 以内 \(g\) 倍数个数。

题目要求找到最大的 \(g\),满足 \(\left\lfloor \frac{a-1}{g}\right\rfloor<\left\lfloor \frac{b}{g}\right\rfloor\land \left\lfloor \frac{c-1}{g}\right\rfloor<\left\lfloor \frac{d}{g}\right\rfloor\)

直接枚举 \(g\) 复杂度过高,所以考虑整除分块,枚举 \(\left\lfloor \frac{b}{g}\right\rfloor\)\(\left\lfloor \frac{d}{g}\right\rfloor\),以枚举 \(\left\lfloor \frac{b}{g}\right\rfloor\) 为例,令这个值为 \(k\),那么找到最大的区间 \([l,r]\) 满足 \(g\in [l,r]\)\(\left\lfloor \frac{b}{g}\right\rfloor=k\),那么当 \(g=r\) 时一定不劣,因为此时 \(k\) 不变且 \(\left\lfloor \frac{a-1}{g}\right\rfloor\) 最小,同时答案 \(g\) 尽可能大。

对于每个块 \([l,r]\) 判断右端点 \(r\) 是否满足上述条件即可,由整除分块分析单组数据复杂度为 \(O(\sqrt V)\)

时间复杂度 \(O(n\sqrt V)\)

Code
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=2e5+10;
constexpr int inf=1e9+10;

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

inline void solve() {
	int a,b,c,d,ret=0;
	read(a);read(b);read(c);read(d);
	for (int L=1,R=1,len=min(b,d);L<=len;L=R+1) {
		int k1=b/L,k2=d/L;
		R=min(b/k1,d/k2);
		if (R*k1>=a&&R*k2>=c) ret=R;
	}
	printf("%d\n",ret);
}

int main() {
	int T;
	read(T);
	while (T--) solve();
	return 0;
}

CF1728E Red-Black Pepper

solution

\(f(x)\)\(x\) 个红辣椒所得到的贡献,那么 \(f(x)\) 是个凸函数,求 \(f(x)\) 是平凡的。

每次询问先找出合法解,再在合法的前提下让红辣椒个数尽可能靠近 \(f(x)\) 最大值对应的 \(x\)

时间复杂度 \(O(n\log n+m\log V)\)

Code
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=3e5+10;
constexpr int inf=1e9+10;

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

int n,m;
int d[N];
ll f[N];

inline int gcd(int x,int y) {return y?gcd(y,x%y):x;}
struct Node{ll x,y;};
inline Node exgcd(int a,int b) {
	if (!b) return {1,0};
	Node res=exgcd(b,a%b);
	return {res.y,res.x-(a/b)*res.y};
}

inline ll calc(int x,int y) {
	if (x<0||y<0||x>n||y>n) return -1;
	return f[x];
}

inline ll solve(int a,int b,int id) {
	int d=gcd(a,b);
	if (n%d) return -1;
	Node res=exgcd(a,b);
	ll x0=res.x*(n/d),y0=res.y*(n/d),dx=b/d,dy=a/d;
	ll xx=x0%dx;xx+=(xx<0?dx:0);
	ll yy=(n-a*xx)/b;
	if (yy<0) return -1;
	ll ret=calc(xx*a,yy*b);
	ll tim1=yy/dy,tim2=(id/a-xx)/dx;
	ll k=min(tim1,tim2);
	xx+=dx*k;yy-=dy*k;
	ret=max(ret,calc(xx*a,yy*b));
	xx+=dx;yy-=dy;
	ret=max(ret,calc(xx*a,yy*b));
	return ret;
}

int main() {
	read(n);
	f(i,1,n) {
		int a,b;read(a);read(b);
		d[i]=b-a;f[n]+=a;
	}
	sort(d+1,d+1+n);
	int id=n;
	F(i,n,1) {
		f[i-1]=f[i]+d[i];
		if (f[i-1]>f[id]) id=i-1;
	}
	read(m);
	while (m--) {
		int x,y;read(x);read(y);
		printf("%lld\n",solve(x,y,id));
	}
	return 0;
}

[POI 2011] SEJ-Strongbox

solution

逆天题目。

容易发现 \(d\) 是密码说明 \(\gcd(d,n)\) 的倍数都是密码。

对于不合法密码 \(x\),所有 \(\gcd(x,n)\) 的因子都不合法。

于是标记 \(\gcd(n,x)\),最后从大到小扫所有因子,若因子 \(k\) 不合法,那么 \(\frac{k}{p}\) 也标记为不合法,其中 \(p\)\(n\) 的质因子且 \(p\mid k\)

最后枚举每个因数,如果它没被标记且满足是密码的数是它的倍数,那么这个数合法,找到最小合法的数 \(x\)\(\frac{n}{x}\) 即为答案。

时间复杂度 \((k\log n+\sqrt n+d(n)\omega(n))\)

Code
#include<cstdio>
#include<algorithm>
#include<unordered_set>
#include<vector>
#include<bitset>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=1e7+10;
constexpr int inf=1e9+10;

inline void readl(ll &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

ll n,m;
inline ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
inline ll lcm(ll x,ll y) {return x/gcd(x,y)*y;}

unordered_set<ll> vis;

inline vector<ll> get_d() {
	vector<ll> ret;
	for (ll i=1;i*i<=n;i++) if (n%i==0) {
		ret.push_back(i);
		if (i*i!=n) ret.push_back(n/i);
	}
	sort(ret.begin(),ret.end());
	return ret;
}

inline vector<ll> get_p() {
	vector<ll> ret;
	ll v=n;
	for (ll i=2;i*i<=n;i++) if (v%i==0) {
		ret.push_back(i);
		while (v%i==0) v/=i;
	}
	if (v>1) ret.push_back(v);
	return ret;
}

inline ll solve(vector<ll> d,vector<ll> p,ll k) {
	int sz=d.size()-1;
	F(i,sz,0) if (vis.count(d[i])) {
		ll x=d[i];
		for (ll k:p) if (x%k==0) vis.insert(x/k);
	}
	for (ll x:d) if (!vis.count(x)&&k%x==0) return n/x;
	return -1;
}

int main() {
	readl(n);readl(m);
	if (m==1) return printf("%lld\n",n),0;
	ll d=0;
	f(i,1,m-1) {
		ll x;readl(x);
		if (!x) return puts("-1"),0;
		vis.insert(gcd(n,x));
	}
	ll k;readl(k);
	printf("%lld\n",solve(get_d(),get_p(),k));
	return 0;
}

[POI 2005] SKO-Knights

solution

考虑对于两个向量 \((a,b),(c,d)\) 所能表示的所有点,横坐标为 \(p\) 时纵坐标的所有合法取值,显然合法的 \(p\) 均为 \(\gcd(a,c)\) 的倍数。

\(ax+cy=p\) 时,\(bx+dy\) 的取值,先找到一组合法解 \((x_0,y_0)\),由二元线性不定方程的通解形式可得,\(x=x_0+\frac{c}{\gcd(a,c)}k,y=y_0-\frac{a}{\gcd(a,c)}k,k\in \mathbb{Z}\),所以有合法的纵坐标取值为 \(b(x_0+\frac{c}{\gcd(a,c)}k)+d(y_0-\frac{a}{\gcd(a,c)}k),k\in \mathbb{Z}\),发现只需要找到一个纵坐标 \(q\) 合法,那么所有合法纵坐标都可以表示为 \(q+(b\frac{c}{\gcd(a,c)}-d\frac{a}{\gcd(a,c)})k,k\in \mathbb{Z}\),即所有合法的相邻纵坐标之间的距离为 \(\left\lvert (b\frac{c}{\gcd(a,c)}-d\frac{a}{\gcd(a,c)}) \right\rvert\),并且这个距离与横坐标取值无关,所以我们可以用两个向量 \((p,q),(0,\left\lvert (b\frac{c}{\gcd(a,c)}-d\frac{a}{\gcd(a,c)}) \right\rvert)\) 来描述这个点集,其中 \(p\) 为最小的合法非负横坐标,即 \(\gcd(a,c)\),目的是表示出所有合法横坐标,\(q\)\(p\) 对应的任意合法纵坐标。

那么我们有两个向量 \(A,B\),其中 \(B\) 为纵向距离向量,考虑如何加入一个向量 \(C\)

\(A,C\) 能表示的点集用向量 \(D,E\) 表示,其中 \(E\) 为纵向距离向量,此时将 \(B\)\(E\) 合并即可,即将纵向距离为 \(B\) 的模长与 \(E\) 的模长的 \(\gcd\)

时间复杂度 \(O(n\log V)\)

Code
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=2e5+10;
constexpr int inf=1e9+10;

inline void read(int &x) {
	x=0;int f=1;
	char ch=getchar();
	while (ch<48) {if(ch=='-')f=-1;ch=getchar();} 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();x*=f;
}

int n;
struct Vector{ll x,y;}A,B;
inline ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
inline ll abss(ll x) {return x<0?-x:x;}

inline Vector exgcd(ll a,ll b) {
	if (!b) return {1,0};
	Vector res=exgcd(b,a%b);
	return {res.y,res.x-(a/b)*res.y};
}

inline pair<Vector,Vector> solve(Vector v1,Vector v2) {
	ll a=v1.x,b=v1.y,c=v2.x,d=v2.y;
	Vector res1,res2;
	res1.x=gcd(a,c);
	if (res1.x) res2.y=abss(b*(c/res1.x)-d*(a/res1.x));
	else res2.y=gcd(b,d);
	Vector ret=exgcd(a,c);
	if (res2.y) res1.y=(ret.x*v1.y+ret.y*v2.y)%res2.y;
	else res1.y=(ret.x*v1.y+ret.y*v2.y);
	if (res1.y<0) res1.y+=res2.y;
	return make_pair(res1,res2);
}

int main() {
	read(n);
	f(i,1,n) {
		int x,y;read(x);read(y);
		pair<Vector,Vector> p=solve(A,{x,y});
		A=p.first;B.y=gcd(p.second.y,B.y);
	}
	printf("%lld %lld\n%lld %lld\n",A.x,A.y,B.x,B.y);
	return 0;
}

[NOI2018] 屠龙勇士

solution

直接用 multiset 模拟得到每次的攻击力,令第 \(i\) 次攻击力为 \(t_i\),那么只需要满足 \(t_i \cdot x \equiv a_i \pmod{p_i} \land t_i \cdot x \ge a_i\)

第二个条件给出了 \(x\) 的下限,令这个下限为 \(mn\),然后先不管它,解决第一个条件。

首先若 \(\gcd(t_i,p_i) \not\mid a_i\) 则无解,否则整个式子同时除以 \(\gcd(t_i,p_i)\),然后两边乘 \(t_i^{-1}\),这样就是一个线性同余方程组的板子。

exCRT 求出 \(x\) 后(无解返回 \(-1\)),令最后模数为 \(p\),那么若 \(x<mn\) 则加上 \(\left\lceil \frac{mn-x}{p}\right\rceil \times p\) 即可。

时间复杂度 \(O(n\log p)\)

Code
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
#define int long long
#define ll __int128
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=2e5+10;
constexpr int inf=1e9+10;

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

inline void readl(ll &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

struct Node{__int128 x,y;};
inline Node exgcd(ll a,ll b) {
	if (!b) return {1,0};
	Node res=exgcd(b,a%b);
	return {res.y,res.x-(a/b)*res.y};
}

inline ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
inline ll inv(ll a,ll p) {
	Node res=exgcd(a,p);
	return (res.x%p+p)%p;
}

int n,m;
ll a[N],p[N];
int w[N],t[N];

inline ll exCRT() {
	ll mn=0;
	f(i,1,n) {
		mn=max(mn,a[i]/t[i]+(a[i]%t[i]!=0));
		a[i]%=p[i];
		ll d=gcd(p[i],t[i]);
		if (a[i]%d!=0) return -1;
		a[i]/=d;p[i]/=d;t[i]/=d;
		a[i]=a[i]*inv(t[i],p[i])%p[i];
	}
	ll x=p[1],y=a[1];
	f(i,2,n) {
		ll c=p[i],d=a[i];
		ll g=gcd(x,c),v=(d-y%c+c)%c;
		if (v%g!=0) return -1;
		c/=g;v/=g;
		y+=(__int128)(v)*inv(x/g,c)%c*x;
		x*=c;y%=x;
	}
	if (y>=mn) return y;
	y+=((mn-y)/x+((mn-y)%x!=0)*x);
	return y;
}

inline void solve() {
	read(n);read(m);
	multiset<int> s;
	f(i,1,n) readl(a[i]);
	f(i,1,n) readl(p[i]);
	f(i,1,n) read(w[i]);
	f(i,1,m) {
		int x;read(x);
		s.insert(x);
	}
	f(i,1,n) {
		multiset<int>::iterator it=s.upper_bound(a[i]);
		if (it!=s.begin()) --it;
		t[i]=(*it);
		s.erase(it);
		s.insert(w[i]);
	}
	printf("%lld\n",(long long)(exCRT()));
}

signed main() {
	int T;
	read(T);
	while (T--) solve();
	return 0;
}

[COCI 2012/2013 #6] BAKTERIJE

solution

下文规定一个细菌的状态为三元组 \((x,y,d)\),即所在坐标以及面对方向。

对于每个细菌,它可能的状态只有 \(4nm\) 个,所以它运动一定时间后一定会走到一个环上,然后在环上不断重复运动,环长不会超过 \(4nm\)

由于 \(K\) 很小,我们可以模拟每个细菌的运动轨迹,并维护它什么时候落入了陷阱,对于每次落入陷阱,我们只需要记录首次到达该状态的时间,以及这个状态在不在环上,若这个状态不在环上,那么考虑这个时间所有细菌是否同时落入陷阱并更新答案,那剩下要考虑的就是同时落入环上陷阱的情况。

考虑每个细菌,枚举落入陷阱时的状态,令第一次抵达这个状态时间为 \(a_i\),环长为 \(p_i\)(再经过 \(p_i\) 的时间会第一次回到这个状态),则这个细菌在运动时间为 \(x\) 时落入陷阱当且仅当 \(x \equiv a_i \pmod{p_i} \land x \ge a_i\),我们先不考虑第二个限制,将多个细菌的第一个限制组成线性同余方程组,并用 exCRT 求解出最小解 \(x_0\) 即最终模数 \(p\),则满足所有细菌同时落入陷阱的时间 \(x=x_0+k \cdot p(k\in \mathbb{Z})\),令所有细菌 \(a_i\) 的最大值为 \(mn\),则 \(x\) 还需要满足 \(x\ge mn\),所以若 \(x_0<mn\) 则返回 \(x_0+\left\lceil \frac{mn-x_0}{p} \right\rceil \times p\) 即可。

时间复杂度 \(O(KNM+4^KK\log V)\)

Code
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define int128 __int128
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=50+10;
constexpr ll inf=(ll)(8e18)+10;

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

struct Node{int128 x,y;};
inline Node exgcd(int128 a,int128 b) {
	if (!b) return {1,0};
	Node res=exgcd(b,a%b);
	return {res.y,res.x-(a/b)*res.y};
}

inline int128 inv(int128 a,int128 p) {
	Node res=exgcd(a,p);
	return (res.x%p+p)%p;
}

struct Faction{ll a,p,mn;};
inline int128 gcd(int128 x,int128 y) {return y?gcd(y,x%y):x;}

inline ll EXCRT(vector<Faction> tmp,ll mn) {
	int128 x=tmp.back().p,y=tmp.back().a;
	tmp.pop_back();
	for (Faction now:tmp) {
		int128 c=now.p,d=now.a;
		int128 g=gcd(x,c),v=(d-y%c+c)%c;
		if (v%g!=0) return inf;
		c/=g;v/=g;
		y+=v*inv(x/g,c)%c*x;
		x*=c;y%=x;
	}
	if (y>=mn) return y;
	y+=((mn-y)/x+((mn-y)%x!=0))*x;
	return y;
}

ll ans=inf;
vector<Faction> f[10];

int n,m,k;
int ex,ey;
int t[N][N],vis[N*N*4];

inline void dfs(int now,vector<Faction> tmp,ll mn) {
	if (now==k+1) return ans=min(ans,EXCRT(tmp,mn)),void();
	for (Faction k:f[now]) {
		tmp.push_back(k);
		dfs(now+1,tmp,max(mn,k.mn));
		tmp.pop_back();
	}
}

inline vector<Faction> solve(int x,int y,int d) {
	static int dis[N][N][4];
	f(i,1,n) f(j,1,m) f(k,0,3) dis[i][j][k]=1e8;
	vector<int> ans_t;
	dis[x][y][d]=0;
	int Rd=-1,mnd=-1;
	while (1) {
		int lst=dis[x][y][d];
		if (x==ex&&y==ey) ans_t.push_back(lst);
		d=(d+t[x][y])%4;
		if (x==1&&d==0) d=2;
		if (y==m&&d==1) d=3;
		if (x==n&&d==2) d=0;
		if (y==1&&d==3) d=1;
		if (d==0) x--;
		if (d==1) y++;
		if (d==2) x++;
		if (d==3) y--;
		if (dis[x][y][d]!=1e8) {
			Rd=lst-dis[x][y][d]+1;
			mnd=dis[x][y][d];
			break;
		}
		dis[x][y][d]=lst+1;
	}
	vector<Faction> ret;
	for (int x:ans_t) {
		if (x>=mnd) ret.push_back({x%Rd,Rd,x});
		else vis[x]++;
	}
	return ret;
}

int main() {
	read(n);read(m);read(k);
	read(ex);read(ey);
	f(T,1,k) {
		static char mp[N][N],op[3];
		int x,y,d;read(x);read(y);
		scanf("%s",op);
		f(i,1,n) scanf("%s",mp[i]+1);
		f(i,1,n) f(j,1,m) t[i][j]=(mp[i][j]-'0');
		if (op[0]=='U') d=0;
		if (op[0]=='R') d=1;
		if (op[0]=='D') d=2;
		if (op[0]=='L') d=3;
		f[T]=solve(x,y,d);
		if (f[T].empty()) return puts("-1"),0;
	}
	f(i,0,n*m*4) if (vis[i]==k) ans=min(ans,(ll)i);
	dfs(1,vector<Faction>(),0);
	printf("%lld\n",(ans==inf)?-1:ans+1);
	return 0;
}
posted @ 2026-09-02 19:03  Ff472130  阅读(6)  评论(0)    收藏  举报