HackerRank - number-game-on-a-tree

Andy and Lily love playing games with numbers and trees. Today they have a treeconsisting of  nodes and  edges. Each edge  has an integer weight, .

Before the game starts, Andy chooses an unordered pair of distinct nodes, , and uses all the edge weights present on the unique path from node  to node  to construct a list of numbers. For example, in the diagram below, Andy constructs a list from the edge weights along the path :

Andy then uses this list to play the following game with Lily:

  • Two players move in alternating turns, and both players play optimally (meaning they will not make a move that causes them to lose the game if some better, winning move exists).
  • Andy always starts the game by removing a single integer from the list.
  • During each subsequent move, the current player removes an integer less than or equal to the integer removed in the last move.
  • The first player to be unable to move loses the game.

For example, if the list of integers is  and Andy starts the game by removing , the list becomes . Then, in Lily's move, she must remove a remaining integer less than or equal to  (i.e., , or ).

The two friends decide to play  games, where each game is in the form of a tree. For each game, calculate the number of unordered pairs of nodes that Andy can choose to ensure he always wins the game.

Input Format

The first line contains a single integer, , denoting the number of games. The subsequent lines describe each game in the following format:

  1. The first line contains an integer, , denoting the number of nodes in the tree.
  2. Each line  of the  subsequent lines contains three space-separated integers describing the respective values of , and  for the  edge connecting nodes  and  with weight .

Constraints

  • Sum of  over all games does not exceed 

Scoring

  • For  of score, the sum of  over all games does not exceed .
  • For  of score, the sum of  over all games does not exceed .

Output Format

For each game, print an integer on a new line describing the number of unordered pairs Andy can choose to construct a list that allows him to win the game.

Sample Input 0

3
5
1 2 2
1 3 1
3 4 1
3 5 2
5
1 2 0
2 3 2
3 4 2
4 5 0
5
1 2 0
1 3 1
3 4 0
3 5 2

Sample Output 0

9
8
10

Explanation 0

Andy and Lily play the following  games:

  1. The first game's tree looks like this: 

    There are  ways to choose , and only one such pair causes Andy to lose the game. If he chooses the pair , the list is . Andy removes  in his first move, and Lily removes the remaining  in the next move; at this point, Andy has no remaining moves and Lily wins. Because Andy will win if he selects any of the other  pairs, we print  on a new line.

  2. The second game's tree looks like this: 

    There are  ways to choose , and two pairs that cause Andy to lose the game:

    • If Andy chooses , the list is . Andy removes  in his first move, and Lily removes the remaining  in the next move; at this point, Andy has no remaining moves and Lily wins.
    • If Andy chooses , the list is . Andy can remove either a  or a  in the first move, but either way Lily will make an optimal choice in her next move that causes Andy to lose. Andy will win if he selects any of the other  pairs, so we print  on a new line.
  3. The third game's tree looks like this: 
     
    There are  ways to choose , and Andy will win the game regardless of which pair he chooses. Thus, we print  on a new line.


此题问你选取两个点,玩游戏,先手必赢的点对有多少个。

玩游戏的规则:

1.玩家每次只能选择小于等于上一次选择的数值的大小。

2.知道某一个玩家无法选择的时候,这个玩家输掉比赛。

先手必赢的情况不难想,只要先手选择一个最小的就是必赢了。但是最小的可能是有偶数个的。

所以再扩展一下就是,如果所有的数都是偶数个,那么先手是必输的(这时后手只需要跟着先手拿就可以了),反之,只要有一个数是奇数个,那么必定先手必赢。(这时,先手拿掉那个奇数,如果有多个奇数,那么只要拿掉那个最小的奇数,后面先手跟着拿就可以了)。

然后,我们直接找存在奇数的不太好搞,相反的点对情况就是所有的数的个数为偶数个。这时候就可以想到异或。但是,并不是异或为0就必定是每个数的个数都是偶数。3个数异或也有可能为0的。这里就直接学习了一个哈希函数。把边重新映射,然后再去异或就没问题了。

相同的两个数异或值为0的。

我们去深搜全部的路径,并且同时异或权值,然后记录每个权值出现的次数。每当一个数出现两次,就会多一个点对,当然组合起来的话,肯定是至少多一个点对啦。

#include 
using namespace std;
typedef unsigned long long ULL;
int n,m,q;
const int MAXN=5e5+7;
const int mod=1e9+7;
vector>edge[MAXN];
mapnum;

ULL Hash(ULL w)
{
    return w*747474747+447474747;
}

void dfs(int u,int fa,ULL w)
{
    num[w]++;
    for(auto it:edge[u])
    {
        int v=it.first;
        ULL ww=it.second;
        if(v==fa)continue;
        dfs(v,u,w^ww);
    }
}
int main()
{
    int i;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;++i)edge[i].clear();
        int u,v,w;
        for(i=0;i>1;
        num.clear();
        dfs(1,0,0);
        for(auto it :num)
        {
            ans-=(1ULL*(it.second-1)*it.second)>>1;
        }
        cout<








你可能感兴趣的:(哈希)