[Every-SG 找规律] BZOJ 1393 [Ceoi2008]knights

题目 还是看官网吧
我们先分析单个游戏
n <script type="math/tex" id="MathJax-Element-28">n</script>很大 我们打表找规律

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

发现很有规律 最后一行一列要特判
写出来就是这样啦

inline int SG(int x,int y){
  if ((x%4==1||x%4==2)&&(y%4==1||y%4==2)) return 0;
  if (n%4==1 && ((x==n&&y!=n-1)||(y==n&&x!=n-1))) return 0;
  if (n%4==0 && x==n && y==n) return 0;
  return 1;
}

我们考虑多个游戏同时进行
对于当前决策者 必败态肯定要尽早结束 必胜态要尽量延迟结束 这样求出最晚结束的一局游戏的胜负就是整个游戏的胜负

我们再来打表找规律 发现必败态的总回合数很有规律

inline int Tlose(int x, int y) {
  if (x==n || y==n) return (x+y-2)/4*2;
  return (x+y-1)/4*2;
}

至于必胜态 我们只要枚举操作决策就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=200005;

int n,K;
int x[N],y[N],sg[N];

inline int SG(int x,int y){
  if ((x%4==1||x%4==2)&&(y%4==1||y%4==2)) return 0;
  if (n%4==1 && ((x==n&&y!=n-1)||(y==n&&x!=n-1))) return 0;
  if (n%4==0 && x==n && y==n) return 0;
  return 1;
}

inline int Tlose(int x, int y) {
  if (x==n || y==n) return (x+y-2)/4*2;
  return (x+y-1)/4*2;
}

const int dx[]={-2,-2,-1,1};
const int dy[]={1,-1,-2,-2};

inline int Twin(int x,int y){
  int maxl=0; int sx,sy;
  for (int k=0;k<4;k++){
    sx=x+dx[k]; sy=y+dy[k];
    if (sx<1 || sy<1 || sx>n || sy>n) continue;
    if (!SG(sx,sy))
      maxl=max(maxl,Tlose(sx,sy));
  }
  return maxl+1;
}

inline void Plose(int x,int y){
  int minw=1<<30; int sx,sy,nx,ny;
  for (int k=0;k<4;k++){
    sx=x+dx[k]; sy=y+dy[k];
    if (sx<1 || sy<1 || sx>n || sy>n) continue;
    if (SG(sx,sy) && Twin(sx,sy)<minw)
      minw=Twin(sx,sy),nx=sx,ny=sy;
  }
  printf("%d %d\n",nx,ny);
}

inline void Pwin(int x,int y){
  int maxl=-1<<30; int sx,sy,nx,ny;
  for (int k=0;k<4;k++){
    sx=x+dx[k]; sy=y+dy[k];
    if (sx<1 || sy<1 || sx>n || sy>n) continue;
    if (!SG(sx,sy) && Tlose(sx,sy)>maxl)
      maxl=Tlose(sx,sy),nx=sx,ny=sy;
  }
  printf("%d %d\n",nx,ny);
}

int main(){
  int maxt=0;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(K); read(n);
  for (int i=1;i<=K;i++){
    read(x[i]),read(y[i]);
    if (sg[i]=SG(x[i],y[i]))
      maxt=max(maxt,Twin(x[i],y[i]));
    else
      maxt=max(maxt,Tlose(x[i],y[i]));
  }
  if (~maxt&1)
    printf("NO\n");
  else{
    printf("YES\n");
    for (int i=1;i<=K;i++)
      if (sg[i])
    Pwin(x[i],y[i]);
      else
    Plose(x[i],y[i]);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值