zoukankan      html  css  js  c++  java
  • 4.3 省选模拟赛 石子游戏 树上博弈

    avatar
    avatar

    注意观察题目 每个点都只能将石子给自己的两个儿子 且石子个数>=1.

    显然 这是一个阶梯NIM. 只有和最后一层的奇偶性相同的层才会有贡献 证明也很显然。

    那么这其实就是近乎NIM游戏了 胜负自然取决于所有有贡献的石子堆的异或和。

    但是 上午我傻了的一点 没有分清SG函数和NIM游戏的联系。

    在NIM游戏中SG函数其实就是每个有贡献的石子堆的石子数。

    再来看这道题 由于异或和一定 暴力枚举移动哪一堆石子 判断是否可行即可。

    这个操作其实是 NIM游戏的证明问题了。解决的方案是 观察一下移动后造成的影响和最终期望的结局来判断移动的石子个数。

    复杂度O(n).算是今天模拟赛最水的题目了 但是我傻了吧唧的没写。

    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ldb long double
    #define pb push_back
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define pii pair<int,int> 
    #define F first
    #define S second
    #define mk make_pair
    #define mod 998244353
    #define RE register
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define ull unsigned long long
    #define P 1000000000000000ll
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=17;
    int T,n,maxx,ans,sum1;
    int a[1<<N],pos[N],sum[1<<N];
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(T);
    	while(T--)
    	{
    		get(n);ans=0;sum1=0;
    		maxx=(1<<n)-1;
    		pos[n]=1;
    		fep(n-1,1,i)pos[i]=pos[i+1]^1;
    		rep(1,maxx,i)
    		{
    			sum[i]=sum[i>>1]+1;
    			get(a[i]);
    			if(pos[sum[i]])ans=ans^a[i];
    		}
    		if(!ans){puts("0");continue;}
    		rep(1,maxx,i)
    		{
    			if(pos[sum[i]])//将res棋子给两个儿子 使得ans^a[i]^now=0  res=a[i]-now;
    			{
    				int now=ans^a[i];
    				if(a[i]<now)continue;
    				sum1=sum1+(sum[i]!=n)+1;
    			}
    			else//将res个棋子给两个儿子 使得a[i<<1]^ans^(a[i<<1]+res)=0
    				//或a[i<<1|1]^ans^(a[i<<1|1]+res)=0; res<=a[i]
    			{
    				//ans=a[i<<1]+res;
    				int res=(ans^a[i<<1])-a[i<<1];
    				if(res>=1&&res<=a[i])++sum1;
    				res=(ans^a[i<<1|1])-a[i<<1|1];
    				if(res>=1&&res<=a[i])++sum1;
    			}
    		}
    		put(sum1);
    	}
    }
    
  • 相关阅读:
    poj 2187 Beauty Contest(旋转卡壳)
    poj 2540 Hotter Colder(极角计算半平面交)
    poj 1279 Art Gallery(利用极角计算半平面交)
    poj 3384 Feng Shui(半平面交的联机算法)
    poj 1151 Atlantis(矩形面积并)
    zoj 1659 Mobile Phone Coverage(矩形面积并)
    uva 10213 How Many Pieces of Land (欧拉公式计算多面体)
    uva 190 Circle Through Three Points(三点求外心)
    zoj 1280 Intersecting Lines(两直线交点)
    poj 1041 John's trip(欧拉回路)
  • 原文地址:https://www.cnblogs.com/chdy/p/12628327.html
Copyright © 2011-2022 走看看