【NOIP2013模拟11.4A组】游乐场

Description

今天是个好日子,小A和他的小伙伴们一起去逛游乐园。这时,游乐园中忽然出现了一个伪装的吸血鬼,小A和他的小伙伴们都惊呆了!小伙伴们马上跑向了游乐园的四面八方。当“吸血鬼”回家吃饭的时候,小A才发现他已经和他的小伙伴们走散了。小A是个路痴,所以他只好站在原地等小伙伴们回来。

我们可以将游乐园视为一个N行M列的矩形,最上面一行为第1行,最左边一列为第1列。每个小伙伴手里都有一张神奇的地图,地图中对应着游乐园的每行每列都有一个写着0-9中某个数字的路标。小A的K位小伙伴们每一秒都会依次进行以下行动:

  1. 读取他所在的位置上的路标X;

  2. 顺时针旋转90度X次;

  3. 如果他面对游乐园外,那就他会再转180度;

  4. 移动到他面对的位置。

小A的视力很糟糕。只有当所有的小伙伴都同时出现在他所在的位置时,他才能和他的小伙伴们团聚。小A等得很心急,所以他求助于你。请你告诉他,他和小伙伴们团聚所需要的时间。

Input

输入的第一行包括正整数N、M和K。

输入的第二行包括正整数X和Y,代表小A的位置。

输入的其他行将分别描述K个小伙伴:

·两个正整数Xi,Yi,代表第i个小伙伴开始时所在的位置。字符Ci,代表该小伙伴开始时面对的方向(U为上,R为右,D为下,L为左);

·由0-9(含)组成的N×M的地图,其中第x行第y列的数字表示该小伙伴地图上(x, y)的位置上的路标。

Output

唯一的一行输出小A和小伙伴们团聚所需要的时间。如果小A和他的小伙伴们永远不会团聚,请输出-1。

Sample Input

输入1:
3 3 1
2 2
1 1 R
010
000
000
输入2:
3 4 2
2 2
3 4 R
2327
6009
2112
3 2 R
1310
2101
1301
输入3:
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

Sample Output

输出1:
3
输出2:
8
输出3:
296

Data Constraint

对于30%的数据,如果小A和他的小伙伴们能够团聚,团聚的总秒数小于10^6;
对于70%的数据,3<=N, M<=40;
对于100%的数据,3<=N, M<=50,1<=K<=5如果小A和他的小伙伴们能够团聚,团聚的总秒数小于10^18。

Solution

首先对每个人进行模拟,会发现他会走成一个环。
因为有四个方向,所以到达目标点也会有最多四个状态。
对于每个这四个状态,记录从开头走到这里的时间ai,还有环的大小bi,如果状态不在环内,bi为0
只有5个人,4个状态,先枚举每个人选哪一个状态 54
那么就会得到一个方程
设时间为t,x为未知数
t=a1+b1x1
t=a2+b2x2
t=ai+bixi
这就是一个典型的中国剩余定理的方程,可以套用公式得出最优解t
但是因为我不懂那个中国剩余定理的公式,所以我用的是扩展欧几里得的解法
每次只算两个方程
如方程1、2:
a1+b1x1=a2+b2x2
b1x1b2x2=a2a1
然后就变成了 ax+by=c 的形式,解这个方程
然后将x或y代入原方程中,得到这两个方程的最优解t’
然后将这两个方程合并,变成
t=t+lcm(b1,b2)x
为什么能变成这样?
因为t’相当于第一个满足原方程的时间,而lcm就是两个都走完环回到原点的最短时间,意义与原方程相同

就这么化简到只剩一个方程,即可得出解
还有b=0或两个b相等的特殊情况,特判即可

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 60
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define INF 100000000000000001ll
using namespace std;
ll n,m,k,x1,y1,a[N][N],b[6][4],c[6][4],d[6],bz[N][N][4],ans=INF;
void hzj(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 gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}
ll getans(ll b1,ll a1,ll b2,ll a2)
{
    ll a=b1,b=-b2,c=a2-a1,x=0,y=0;
    if(b1==0&&b2==0)
    {
        if(a2==a1) return a2;else return INF;
    }
    if(b1==0)
    {
        if(b>c&&c%b==0) return max(a1,a2);else return INF;
    }
    if(b2==0)
    {
        if(c>a&&c%a==0) return max(a1,a2);else return INF;
    }
    if(b1==b2)
    {
        if(abs(a2-a1)%b1==0) return max(a1,a2);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 a1+b1*x;
}
void pd()
{
    ll q[6],w[6];
    fo(i,1,k) q[i]=b[i][d[i]],w[i]=c[i][d[i]];
    if(k==1)
    {
        ans=min(ans,q[1]);
        return;
    }
    fo(i,1,k-1)
    {
        q[i+1]=getans(w[i],q[i],w[i+1],q[i+1]);
        if(gcd(w[i],w[i+1])==0) w[i+1]=0;else w[i+1]=w[i]*w[i+1]/gcd(w[i],w[i+1]);
    }
    ans=min(ans,q[k]);
}
void dg(ll x)
{
    if(x>k) {pd();return;}
    fo(i,0,3) 
    if(b[x][i]!=0) d[x]=i,dg(x+1);
}
int main()
{
    freopen("park.in","r",stdin);
    freopen("park.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k); 
    scanf("%lld%lld\n",&x1,&y1);
    fo(l,1,k)
    {
        char ch;ll x,y,z,lh,jy;
        scanf("%lld %lld %c\n",&x,&y,&ch);
        if(ch=='U') z=0;
        if(ch=='R') z=1;
        if(ch=='D') z=2;
        if(ch=='L') z=3;
        fo(i,1,n)
        {
            fo(j,1,m) a[i][j]=getchar()-48;
            scanf("\n");
        }
        memset(bz,0,sizeof(bz));
        fo(i,0,3) b[l][i]=0;
        fo(i,1,2147483647)
        if(!bz[x][y][z])
        {
            bz[x][y][z]=i;
            if(x==x1&&y==y1) b[l][z]=i;
            hzj(x,y,z);
        }
        else
        {
            lh=i-bz[x][y][z];
            jy=bz[x][y][z];
            break;
        }
        fo(i,0,3) if(b[l][i]>=jy) c[l][i]=lh;else c[l][i]=0;
    }
    dg(1);
    if(ans==INF) ans=-1;
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值