游乐园(中国剩余定理)

游乐园
时间限制: 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 个方程 x % a i = b i ,求 x 的最小正整数解。
构造:当 a i 两两互质时,我们可以构造出x。
M = i = 1 n a i ,如果 x 是一个解,则 x + M 也是一个合法的解,反之亦然。
M i = j = 1 , j i n a j M i 1 表示 M i 关于 a i 的逆元。
x = i = 1 n b i M i M i 1 % M
接下来证明 x 的确是方程组的一个解。
对于第 i 个方程,当 j = i 时, b j M j M j 1 % a i = b i
j i 时, M j % a i = 0 ,因此 b j M j M j 1 % a i = 0
所以 x % a i = b i 成立。
那么不互质的情况呢?
不妨假设我们要解方程 x % a 1 = b 1 x % a 2 = b 2
x = k 1 a 1 + b 1 = k 2 a 2 + b 2
化简得 k 1 a 1 k 2 a 2 = b 2 b 1 ,利用 e x g c d 求出 x 的一个解 r
那么 x % l c m ( a 1 , a 2 ) = r
对于更多的方程,一一合并即可。
好,开始扯游乐园这道题了。
首先裂点,将每一个点拆分成 4 个,分别表示不同的朝向。
可以发现每个人走的路径存在循环节,且为一个 ρ 形循环。
枚举每一个人到达终点时的朝向,设环的大小为 l e n i ,第一次到达该点的时刻为 t i
若该点不在环上,则答案必须为 t i ,否则答案为 k l e n i + t i
用中国剩余定理求解即可。
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); 
} 

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/81042382