时间限制: 1 Sec 内存限制: 128 MB
题目描述
今天是个好日子,小A和他的小伙伴们一起去逛游乐园。这时,游乐园中忽然出现了一个伪装的吸血鬼,小A和他的小伙伴们都惊呆了!小伙伴们马上跑向了游乐园的四面八方。当“吸血鬼”回家吃饭的时候,小A才发现他已经和他的小伙伴们走散了。小A是个路痴,所以他只好站在原地等小伙伴们回来。
我们可以将游乐园视为一个N行M列的矩形,最上面一行为第1行,最左边一列为第1列。每个小伙伴手里都有一张神奇的地图,地图中对应着游乐园的每行每列都有一个写着0-9中某个数字的路标。小A的K位小伙伴们每一秒都会依次进行以下行动:
1.读取他所在的位置上的路标X;
2.顺时针旋转90度X次;
3.如果他面对游乐园外,那就他会再转180度;
4.移动到他面对的位置。
小A的视力很糟糕。只有当所有的小伙伴都同时出现在他所在的位置时,他才能和他的小伙伴们团聚。小A等得很心急,所以他求助于你。请你告诉他,他和小伙伴们团聚所需要的时间。
输入
输入的第一行包括正整数N、M和K。
输入的第二行包括正整数X和Y,代表小A的位置。
输入的其他行将分别描述K个小伙伴:
·两个正整数Xi,Yi,代表第i个小伙伴开始时所在的位置。字符Ci,代表该小伙伴开始时面对的方向(U为上,R为右,D为下,L为左);
·由0-9(含)组成的N×M的地图,其中第x行第y列的数字表示该小伙伴地图上(x, y)的位置上的路标。
输出
唯一的一行输出小A和小伙伴们团聚所需要的时间。如果小A和他的小伙伴们永远不会团聚,请输出-1。
样例输入
3 3 1
2 2
1 1 R
010
000
000
3 4 2
2 2
3 4 R
2327
6009
2112
3 2 R
1310
2101
1301
4 4 3
4 3
1 1 U
1001
0240
3322
2327
1 3 L
9521
2390
3020
2421
2 2 D
3397
2013
1102
7302
样例输出
3
8
296
提示
【数据范围】
对于30%的数据,如果小A和他的小伙伴们能够团聚,团聚的总秒数小于10^6;
对于70%的数据,3<=N, M<=40;
对于100%的数据,3<=N, M<=50,1<=K<=5如果小A和他的小伙伴们能够团聚,团聚的总秒数小于10^18。
题解:
在扯这道题之前,先扯一波中国剩余定理。
科普时间:
一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:
有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。《孙子算经》中首次提到了同余方程组问题,以及以上具体问题的解法,因此在中文数学文献中也会将中国剩余定理称为孙子定理。
正题:
问题描述:用数学的语言来说,就是给定
n
n
个方程%
ai=bi
a
i
=
b
i
,求
x
x
的最小正整数解。
构造:当两两互质时,我们可以构造出x。
令
M=∏ni=1ai
M
=
∏
i
=
1
n
a
i
,如果
x
x
是一个解,则也是一个合法的解,反之亦然。
令
Mi=∏nj=1,j≠iaj
M
i
=
∏
j
=
1
,
j
≠
i
n
a
j
,
M−1i
M
i
−
1
表示
Mi
M
i
关于
ai
a
i
的逆元。
则
x=∑ni=1biMiM−1i
x
=
∑
i
=
1
n
b
i
M
i
M
i
−
1
%
M
M
。
接下来证明的确是方程组的一个解。
对于第
i
i
个方程,当时,
bjMjM−1j
b
j
M
j
M
j
−
1
%
ai=bi
a
i
=
b
i
。
当
j≠i
j
≠
i
时,
Mj
M
j
%
ai=0
a
i
=
0
,因此
bjMjM−1j
b
j
M
j
M
j
−
1
%
ai=0
a
i
=
0
。
所以
x
x
%成立。
那么不互质的情况呢?
不妨假设我们要解方程
x
x
%和
x
x
%。
则
x=k1a1+b1=k2a2+b2
x
=
k
1
a
1
+
b
1
=
k
2
a
2
+
b
2
。
化简得
k1a1−k2a2=b2−b1
k
1
a
1
−
k
2
a
2
=
b
2
−
b
1
,利用
exgcd
e
x
g
c
d
求出
x
x
的一个解。
那么
x
x
%。
对于更多的方程,一一合并即可。
好,开始扯游乐园这道题了。
首先裂点,将每一个点拆分成
4
4
个,分别表示不同的朝向。
可以发现每个人走的路径存在循环节,且为一个形循环。
枚举每一个人到达终点时的朝向,设环的大小为
leni
l
e
n
i
,第一次到达该点的时刻为
ti
t
i
。
若该点不在环上,则答案必须为
ti
t
i
,否则答案为
k∗leni+ti
k
∗
l
e
n
i
+
t
i
。
用中国剩余定理求解即可。
Code:
C
o
d
e
:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 60
#define ll long long
#define INF 100000000000000000
using namespace std;
ll n,m,k,x1,y1,a[N][N],b[6][4],c[6][4],d[6],f[N][N][4],ans=INF;
void work(ll &x,ll &y,ll &z)
{
(z+=a[x][y])%=4;
if(x==1&&z==0)z=2;
if(y==1&&z==3)z=1;
if(x==n&&z==2)z=0;
if(y==m&&z==1)z=3;
if(z==0)x--;
if(z==1)y++;
if(z==2)x++;
if(z==3)y--;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1,y=0;return;
}
exgcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
}
ll getans(ll len1,ll st1,ll len2,ll st2)
{
ll a=len1,b=-len2,c=st2-st1,x=0,y=0;
if(len1==0&&len2==0)
if(st2==st1)return st2;else return INF;
if(len1==0)
if(b>c&&c%b==0)
return max(st1,st2);else return INF;
if(len2==0)
if(c>a&&c%a==0)
return max(st1,st2);else return INF;
if(len1==len2)
if(abs(st2-st1)%len1==0)
return max(st1,st2);else return INF;
ll g=__gcd(a,b);
if(c%g!=0)return INF;
exgcd(a,b,x,y);
c/=g;x*=c;
b=abs(b);b/=g;
if(x<0)x=(b+x%b);
x%=b;
return st1+len1*x;
}
void find(ll x)
{
if(x>k)
{
ll st[6],len[6];
for(int i=1;i<=k;i++)
st[i]=b[i][d[i]],len[i]=c[i][d[i]];
if(k==1)
{
ans=min(ans,st[1]);
return;
}
for(int i=1;i<=k-1;i++)
{
st[i+1]=getans(len[i],st[i],len[i+1],st[i+1]);
if(__gcd(len[i],len[i+1])==0)len[i+1]=0;
else len[i+1]=len[i]*len[i+1]/__gcd(len[i],len[i+1]);
}
ans=min(ans,st[k]);
}
for(int i=0;i<=3;i++)
if(b[x][i]!=0)d[x]=i,find(x+1);
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&k);
scanf("%lld%lld",&x1,&y1);
for(int l=1;l<=k;l++)
{
char ch;ll x,y,z,ring,_ring;
scanf("%lld %lld %c",&x,&y,&ch);
if(ch=='U')z=0;
if(ch=='R')z=1;
if(ch=='D')z=2;
if(ch=='L')z=3;
for(int i=1;i<=n;i++)
{
char ch[105];
scanf("%s",ch);
for(int j=1;j<=m;j++)
a[i][j]=ch[j-1]-48;
}
memset(f,0,sizeof(f));
for(int i=0;i<=3;i++)b[l][i]=0;
for(int i=1;;i++)
if(!f[x][y][z])
{
f[x][y][z]=i;
if(x==x1&&y==y1)b[l][z]=i;
work(x,y,z);
}else
{
ring=i-f[x][y][z];
_ring=f[x][y][z];
break;
}
for(int i=0;i<=3;i++)
if(b[l][i]>=_ring)c[l][i]=ring;
else c[l][i]=0;
}
find(1);
if(ans==INF)ans=-1;
printf("%lld",ans);
}