数论做题记录
#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;
}

浙公网安备 33010602011771号