P2575 高手过招
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2575 高手过招相关的知识,希望对你有一定的参考价值。
题意:
AKN玩游戏玩累了,于是他开始和同伴下棋了,玩的是跳棋!对手是wwx!这两位上古神遇在一起下棋,使得棋局变得玄幻莫测,高手过招,必有一赢,他们都将用最佳策略下棋,现在给你一个n*20的棋盘,以及棋盘上有若干个棋子,问谁赢?akn先手!
游戏规则是这样的:
对于一个棋子,能将它向右移动一格,如果右边有棋子,则向右跳到第一个空格,如果右边没有空格,则不能移动这个棋子,如果所有棋子都不能移动,那么将输掉这场比赛。
题解:
注意题目意思,题目说的是每个棋子只能向右移动一格,也就是说棋盘的每一行是独立的,所以我们求出每一行的sg值,然后全部异或起来
对于每一行我们来分析:根据题目意思我们可以得知,一次操作中,棋子是跳到右侧第一个空格处,如果右侧没有空格就说明该棋子不能动,所以我们从右侧开始,每次找到遇到空格就记录,然后往左找,找到棋子,就将该棋子跳到记录的空格上,相当于执行了一步操作,得到新状态,然后查找新状态的答案,终状态就是所有棋子都不能动,输掉游戏
我们利用mex运算来求sg函数,对于一个状态x,我们求出x的后继局面的所有sg值,根据mex运算可以求出sg[x]的值。
状态x我们可以用二进制来实现,因为每个位置只有存在棋子和不存在棋子两个情况
这个题很不错,很考验思维,解法也很妙
复杂度:状态数 * 转移
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
const int maxn=2e6+9;
int sg[maxn];
int t,n;
int dfs(int x){
if(sg[x]!=-1)return sg[x];
int vis[21];
memset(vis,0,sizeof(vis));
int last0=-1;//最近的一个0的位置
for(int j=19;j>=0;j--){
if((x>>j)&1){//如果第j位有棋子
if(last0!=-1){//如果右侧有0,
vis[dfs(x^(1<<j)^(1<<last0))]=1;
//棋子移动一步到空格位置
}
}
else last0=j;
}
for(int i=0;i<=20;i++){
if(vis[i]==0)return sg[x]=i;
}
}
int main()
{
cin>>t;
memset(sg,-1,sizeof(sg));
while(t--){
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
int x=0,col,m;
cin>>m;
while(m--){
cin>>col;
col--;
x|=(1<<col);
//最左边是第零列
}
ans^=dfs(x);
}
if(ans==0)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
}
以上是关于P2575 高手过招的主要内容,如果未能解决你的问题,请参考以下文章