博弈论专题

先简单的介绍一下^
0^0=0;
0^1=1;
1^0=1;
1^1=0;

1.一道非常经典的博弈论题目
链接 https://www.acwing.com/problem/content/893/
在这里插入图片描述
对于这题我们只需要
int res=0;
将res与每一堆的石子数量异或一下
最后判断res是不是0;
是0则必败,不是0则必胜;

#include <bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
    int n,x;
    int t; cin>>t;
    while(t--)
    {
        cin>>n;
    int res=0;
    for(int i=1;i<=n;i++) 
    {
        cin>>x;
        res ^=x;
    }
    if(res==0) cout<<"Second"<<endl;
    else cout<<"First"<<endl;
    //system("pause");
    }
    system("pause");
    return 0;
}

题目链接
https://ac.nowcoder.com/acm/contest/26125/A
在这里插入图片描述
这道题刚开始一点思路没有,后突然发现
他的每一次操作都是取奇数个石子;
这样的话就意味着
两个人经过一轮操作 取走了偶数个石子,如果原本是奇数个,那么最后一次操作一定是先手的,反之最后一次操作一定是后手的

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        //cin>>n>>m;
        if((n+m)%2==1) cout<<"win"<<endl;
        else cout<<"lose"<<endl;
    }
  //  system("pause");
    return 0;
}

题目链接
https://ac.nowcoder.com/acm/contest/26125/B
在这里插入图片描述
这道题我犯了两个错误,
第一:我把操作:将第X堆石堆的数量改为有,看成了减去y;
这导致了我测样列找错了很久,不可饶恕的错误;

第二:我没有注意到q是1e5的,写了个o(n^2)暴力,最后tle了;
这是t了的代码

在这里插入代码片#include <bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N];
int main()
{
    int n,q;
    int x,y,m=1;
    cin>>n>>q;
    int res;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=q;i++) 
    {
        res=0;
        cin>>x>>y;
        a[x]=y;
        
            for(int i=1;i<=n;i++)
            {
                res^=a[i];
            }  
            if(res)  cout<<"Kan"<<endl;
            else cout<<"Li"<<endl;
        
        // else
        // {
        //     if(res) cout<<"Kan"<<endl;
        //     else cout<<"Li"<<endl;  
        // }     
    }
    //system("pause");
    return 0;
}

那么我们该如何改进呢,这里要用到一个小技巧
a异或x再异或x=a;
所以我们完全可以先预处理得到所有值的异或值
再对每一次的操作进行处理,这样只需要o(n),是不可能被卡时间的

#include <bits/stdc++.h>
#include <stdlib.h>
using namespace std;
const int N=1000010;
int a[N];
int main()
{
    int n,q;
    int x,y,m=1;
    cin>>n>>q;
    int res=0;
    for(int i=1;i<=n;i++) 
    {
        cin>>a[i];
        res^=a[i];
    }
    for(int i=1;i<=q;i++) 
    {
        cin>>x>>y;
        res^=a[x];
        res^=y;
        a[x]=y;
        if(res)  cout<<"Kan"<<endl;
        else cout<<"Li"<<endl;
    }   
    system("pause");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值