BZOJ2647 : [Neerc2011]Journey

Claris發表於2018-03-10

$|x|+|y|=\max(x+y,x-y,-x+y,-x-y)$,設$f[i][j]$表示在$(0,0)$,朝向方向$j$,執行第$i$條指令後的資訊:

$cir$:是否陷入迴圈

$d$:朝向

$x,y$:座標

$v_0$:$\max(x+y)$

$v_1$:$\max(x-y)$

$v_2$:$\max(-x+y)$

$v_3$:$\max(-x-y)$

然後記憶化搜尋,當陷入迴圈時不再執行後面的指令。

用棧維護所有正在計算的狀態,若發現迴圈,則計算迴圈的$x$和$y$之和,若為$0$則是迴圈,否則會走到無限遠處。

時間複雜度$O(n^3)$。

 

#include<cstdio>
#include<string>
#include<iostream>
#include<cstdlib>
using namespace std;
const int N=110,Base=100000000,MAXL=32;
int n,i,j,a[N],q[N*4][2],in[N][4];string b[N][N];bool vis[N][4],cir[N][4];
inline int max(int a,int b){return a>b?a:b;}
struct Num{
  int a[MAXL],len,fu;
  void init(){len=1,fu=a[1]=0;}
  Num(){init();}
  bool iszero(){return len==1&&!a[1];}
  Num operator+(const Num&b){
    Num c;
    c.len=max(len,b.len)+2;
    int i;
    for(i=1;i<=c.len;i++)c.a[i]=0;
    if(fu==b.fu){
      for(i=1;i<=len;i++)c.a[i]=a[i];
      for(i=1;i<=b.len;i++)c.a[i]+=b.a[i];
      for(i=1;i<=c.len;i++)if(c.a[i]>=Base)c.a[i+1]++,c.a[i]-=Base;
      while(c.len>1&&!c.a[c.len])c.len--;
      c.fu=fu;
    }else{
      bool flag=0;
      if(len==b.len){
        for(i=len;i;i--)if(a[i]!=b.a[i]){
          if(a[i]>b.a[i])flag=1;
          break;
        }
      }else{
        if(len>b.len)flag=1;
      }
      if(flag){
        for(i=1;i<=len;i++)c.a[i]=a[i];
        for(i=1;i<=b.len;i++)c.a[i]-=b.a[i];
        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=Base;
        while(c.len>1&&!c.a[c.len])c.len--;
        c.fu=fu;
      }else{
        for(i=1;i<=b.len;i++)c.a[i]=b.a[i];
        for(i=1;i<=len;i++)c.a[i]-=a[i];
        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=Base;
        while(c.len>1&&!c.a[c.len])c.len--;
        c.fu=b.fu;
      }
    }
    if(c.iszero())c.init();
    return c;
  }
  void operator+=(const Num&b){*this=*this+b;}
  Num operator-(const Num&b){
    Num c;
    c.len=max(len,b.len)+2;
    int i;
    for(i=1;i<=c.len;i++)c.a[i]=0;
    if(fu!=b.fu){
      for(i=1;i<=len;i++)c.a[i]=a[i];
      for(i=1;i<=b.len;i++)c.a[i]+=b.a[i];
      for(i=1;i<=c.len;i++)if(c.a[i]>=Base)c.a[i+1]++,c.a[i]-=Base;
      while(c.len>1&&!c.a[c.len])c.len--;
      c.fu=fu;
    }else{
      bool flag=0;
      if(len==b.len){
        for(i=len;i;i--)if(a[i]!=b.a[i]){
          if(a[i]>b.a[i])flag=1;
          break;
        }
      }else{
        if(len>b.len)flag=1;
      }
      if(flag){
        for(i=1;i<=len;i++)c.a[i]=a[i];
        for(i=1;i<=b.len;i++)c.a[i]-=b.a[i];
        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=Base;
        while(c.len>1&&!c.a[c.len])c.len--;
        c.fu=fu;
      }else{
        for(i=1;i<=b.len;i++)c.a[i]=b.a[i];
        for(i=1;i<=len;i++)c.a[i]-=a[i];
        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=Base;
        while(c.len>1&&!c.a[c.len])c.len--;
        c.fu=b.fu^1;
      }
    }
    if(c.iszero())c.init();
    return c;
  }
  void operator-=(const Num&b){*this=*this-b;}
  bool operator<(const Num&b){
    if(fu!=b.fu)return fu;
    if(fu){
      if(len!=b.len)return len>b.len;
      for(int i=len;i;i--)if(a[i]!=b.a[i])return a[i]>b.a[i];
    }else{
      if(len!=b.len)return len<b.len;
      for(int i=len;i;i--)if(a[i]!=b.a[i])return a[i]<b.a[i];
    }
    return 0;
  }
  void write(){
    if(fu)putchar('-');
    printf("%d",a[len]);
    for(int i=len-1;i;i--)printf("%08d",a[i]);
  }
  void set(int x){
    fu=0;
    if(x<0)x=-x,fu=1;
    len=1;
    a[1]=x;
  }
}zero,one,x,y;
inline void up(Num&a,const Num&b){if(a<b)a=b;}
struct E{
  int d;Num x,y,v0,v1,v2,v3;
  void left(){d=(d+1)&3;}
  void right(){d=(d+3)&3;}
  void init(int _d){
    d=_d;
    x.set(0);
    y.set(0);
    v0.set(0);
    v1.set(0);
    v2.set(0);
    v3.set(0);
  }
  void go(){
    if(d==0)x+=one;
    if(d==1)y+=one;
    if(d==2)x-=one;
    if(d==3)y-=one;
    up(v0,x+y);
    up(v1,x-y);
    up(v2,y-x);
    up(v3,zero-x-y);
  }
  void merge(const E&b){
    d=b.d;
    up(v0,x+y+b.v0);
    up(v1,x-y+b.v1);
    up(v2,y-x+b.v2);
    up(v3,zero-x-y+b.v3);
    x+=b.x;
    y+=b.y;
  }
  void write(){
    up(v0,v1);
    up(v0,v2);
    up(v0,v3);
    v0.write();
  }
}f[N][4];
inline int cal(const string&s){
  int t=0;
  for(int i=1;i<s.size();i++)t=t*10+s[i]-'0';
  return t;
}
inline void check(int l,int r){
  for(x.set(0),y.set(0);l<=r;l++)x+=f[q[l][0]][q[l][1]].x,y+=f[q[l][0]][q[l][1]].y;
  if(x.iszero()&&y.iszero())return;
  puts("Infinity");
  exit(0);
}
void cal(int x,int y,int d){
  if(vis[x][y])return;
  vis[x][y]=1;
  q[in[x][y]=d][0]=x;
  q[d][1]=y;
  f[x][y].init(y);
  for(int i=0;i<a[x];i++){
    if(b[x][i]=="GO")f[x][y].go();
    else if(b[x][i]=="LEFT")f[x][y].left();
    else if(b[x][i]=="RIGHT")f[x][y].right();
    else{
      int A=cal(b[x][i]),B=f[x][y].d;
      if(in[A][B]){
        check(in[A][B],d);
        cir[x][y]=1;
      }else{
        cal(A,B,d+1);
        f[x][y].merge(f[A][B]);
        if(cir[A][B])cir[x][y]=1;
      }
      if(cir[x][y])break;
    }
  }
  in[x][y]=0;
}
int main(){
  zero.set(0);
  one.set(1);
  cin>>n;
  for(i=1;i<=n;i++){
    cin>>a[i];
    for(j=0;j<a[i];j++)cin>>b[i][j];
  }
  cal(1,0,1);
  f[1][0].write();
  return 0;
}