【题解】 Codeforces 919F A Game With Numbers(拓扑排序+博弈论+哈希)

懒得复制,戳我戳我

Solution:


说一点之前打错的地方:

  • 连边存的是hash后的数组下标
 if(ans[ num( C[a.hash()] , C[b.hash()] ) ]==1){
      if(f==0)printf("Alice\n");else printf("Bob\n");
      continue;
    }
    if(ans[ num( C[a.hash()] , C[b.hash()] ) ]==-1){
      if(f==0)printf("Bob\n");else printf("Alice\n");
      continue;
    }
  • 每个点存的是A状态与B状态,A操作的必胜还是必输态
  • 然后就是一个要注意的点:我们是反向存边,由后状态推向先状态,如果后状态为必输态,那么先状态一定为必胜态,如果先状态的所有可以达到的后状态都为必胜态,那么这个先状态是必输态
  • 这题思路比较明确,就是一些代码细节要注意吧,还有因为这题学会了\(Struct\)的骚操作

Code:

//It is coded by Ning_Mew on 3.27
#include<bits/stdc++.h>
using namespace std;

const int maxn=400000+10;

int n,f;
int S[maxn],C[maxn],ct=0;
int head[maxn],cnt=0,in[maxn],ans[maxn];
struct Edge{int nxt,to;}edge[(maxn<<6)+5];

void add(int from,int to){
  in[to]++;
  edge[++cnt].nxt=head[from];
  edge[cnt].to=to;
  head[from]=cnt;
}

//bool cmp(const int &xx,const int &yy){return xx<yy;}
struct hs{
  int a[8];
  hs(){memset(a,0,sizeof(a));}
  hs(int x){for(int i=7;i>=0;i--){a[i]=x%5;x=x/5;}}
  hs(int *_a){for(int i=7;i>=0;i--)a[i]=_a[i];}
  void rd(){for(int i=0;i<=7;i++)scanf("%d",&a[i]);}
  void st(){sort(a,a+8);}
  int hash(){
    int ans=0;
    for(int i=0;i<=7;i++)ans=ans*5+a[i];
    return ans;
  }
};

void dfs(int pl,int last,int h){
  if(pl==8){++ct;S[ct]=h;C[h]=ct;return;}
  for(int i=last;i<=4;i++)dfs(pl+1,i,h*5+i);
}
int num(int x,int y){return (x-1)*ct+(y-1);}
void prework(){
  dfs(0,0,0);
  for(int i=1;i<=ct;i++){
    for(int j=1;j<=ct;j++){
      hs a(S[i]),b(S[j]);
      for(int pi=0;pi<=7;pi++)if(a.a[pi]){
      for(int pj=0;pj<=7;pj++)if(b.a[pj]){
          hs c(a.a);
          c.a[pi]=(a.a[pi]+b.a[pj])%5;
          c.st();int tmp=C[c.hash()];
          add( num( j,tmp ),num( i,j ) );
        }
    }
    }
  }
  queue<int>Q;
  while(!Q.empty())Q.pop();
  //-1 lose 1 win 0 deal
  for(int i=2;i<=ct;i++)ans[ num(i,1) ]=-1,Q.push( num(i,1) );
  while(!Q.empty()){
    int u=Q.front();Q.pop();
    for(int i=head[u];i!=0;i=edge[i].nxt){
      int v=edge[i].to;
      if(ans[v]!=0)continue;
      if(ans[u]==-1){ans[v]=1;Q.push(v);}
      else{
    in[v]--;
    if(in[v]==0){ans[v]=-1;Q.push(v);}
      }
    }
  }return;
}

int main(){
  memset(ans,0,sizeof(ans));
  prework();
  scanf("%d",&n);
  hs a,b;
  for(int i=1;i<=n;i++){
    scanf("%d",&f);
    a.rd();b.rd();a.st();b.st();
    if(f==1)swap(a,b);
    if(ans[ num( C[a.hash()] , C[b.hash()] ) ]==1){
      if(f==0)printf("Alice\n");else printf("Bob\n");
      continue;
    }
    if(ans[ num( C[a.hash()] , C[b.hash()] ) ]==-1){
      if(f==0)printf("Bob\n");else printf("Alice\n");
      continue;
    }
    printf("Deal\n");
  }
  return 0;
}

转载于:https://www.cnblogs.com/Ning-Mew/p/8658440.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值