zoukankan      html  css  js  c++  java
  • [HDU5996]dingyeye loves stones

    题目

    点这里看题目。

    分析

    不难想到,这个问题实际上可以按照深度来划分(根的深度为 0),于是这就是一个阶梯 Nim 的问题。

    阶梯 Nim 相当经典,它的模型是:

    (n) 堆石子,编号为 (1sim n),第 (i) 堆有 (a_i) 个石子( (a_i>0) )。每一轮玩家可以选择任意非空的一堆 (k) ,并且可以移动任意多且不为零的石子至 (k-1) 堆(移动第 1 堆的石子相当于直接丢掉它们)。请问先手是否必胜?

    问题的结论是:

    阶梯 Nim 等价于对奇数堆的石子做 Nim 游戏。

    考虑这样的过程:

    1. 如果对手移动奇数堆的石子,我们就按照 Nim 的策略来移动。这样每次操作后,奇数堆的石子会移动到偶数堆里面,奇数堆就是正常的 Nim 过程。
    2. 如果对手不按常理出牌,移动了偶数堆(第 (2n) 堆)的 (k) 个石子。那么我们就可以在 (2n-1) 堆里面,移动恰好 (k) 个石子至第 (2n-2) 堆。最后,要么这 (k) 个石子被丢掉,要么 (k) 个石子移动到偶数堆里,这样奇数堆的石子照样不会被影响。

    这就是阶梯 Nim 的解决方案。实际上,这个结论是告诉我们,阶梯 Nim 的 SG 和是各个奇数位置的堆的异或和

    回到原题。我们认为根的深度是 0 ,看做是 "垃圾桶" (也就是石子丢弃的位置)。对于同一深度上石子堆,移动它们的过程就相当于 Nim 的过程,于是某一深度的 SG 值就是该层上的石子的异或和;对于不同的深度,我们可以将它们看成是阶梯 Nim 的问题,于是整个游戏的 SG 值就是奇数深度的 SG 值的异或值。

    代码:

    #include <cstdio>
    
    const int MAXN = 1e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
        x = 0;char s = getchar();int f = 1;
        while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
        while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
        x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
        if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
        if( 9 < x ){ write( x / 10 ); }
        putchar( x % 10 + '0' );
    }
    
    struct Edge
    {
        int to, nxt;
    }Graph[MAXN << 1];
    
    int dep[MAXN];
    int head[MAXN], num[MAXN];
    int N, cnt, Nim;
    
    void AddEdge( const int from, const int to )
    {
        Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
        head[from] = cnt;
    }
    
    void DFS( const int u, const int fa )
    {
        if( ( dep[u] = dep[fa] + 1 ) % 2 == 0 ) Nim ^= num[u];
        for( int i = head[u] ; i ; i = Graph[i].nxt )
            DFS( Graph[i].to, u );
    }
    
    void Clean()
    {
        Nim = cnt = 0;
        for( int i = 0 ; i <= N ; i ++ )
            head[i] = dep[i] = num[i] = 0;
    }
    
    int main()
    {
        int T;
        read( T );
        while( T -- )
        {
            read( N ), Clean();
            for( int i = 1, fa ; i < N ; i ++ ) read( fa ), AddEdge( fa, i );
            for( int i = 0 ; i < N ; i ++ ) read( num[i] );
            DFS( 0, 0 );
            
            puts( Nim ? "win" : "lose" );
        }
        return 0;
    }
    
  • 相关阅读:
    动态传参
    函数的介绍
    文件的操作
    send email with formatted table
    minimize and close window with customed winform
    python algorithm
    something important about docker
    book list
    which language is suitable for what to do
    Find Duplicate Items in list fast
  • 原文地址:https://www.cnblogs.com/crashed/p/13746175.html
Copyright © 2011-2022 走看看