1. 程式人生 > 實用技巧 >Xor 思維題

Xor 思維題

Xor 思維題

題目描述

\(Q\)與小\(T\)正在玩一棵樹。這棵樹有\(n\)個節點,編號為 \(1\)\(2\) \(3...n\),由\(n-1\)條邊連線,每個節點有一個權值\(w_i\)

在這個遊戲中,小 \(Q\) 需要選擇一些節點。他可以選擇任意個數的點(小\(Q\)一定會選擇最優策略),但是一條邊連線的兩個節點不能同時被選。

當小\(Q\)選完後,小\(T\)將選擇剩下的節點。這樣這棵樹上的每個點都將被小\(Q\)或者小\(T\)選擇。

最後兩人的分數分別為自己選擇的點的權值異或和,分數大的一方獲勝,當然有可能是平局。

輸入格式

第一行一個整數\(T(T \leq 20)\)

,表示測試資料組數

接下來\(T\)組,對於每一組,第一行一個整數\(n\)

第二行有\(n\)個整數,為\(w_1,w_2...w_n\)

接下來\(n-1\)行,每行兩個整數\(x\)\(y\),表示\(x\)\(y\)

之間有一條邊連線

輸出格式

對於每一組,答案只有一行,如果小\(Q\)獲勝輸出\(Q\),小\(T\)獲勝輸出\(T\),如果平局輸出\(D\)

樣例

樣例輸入

2
3
2 2 2
1 2
1 3
4
7 1 4 2
1 2
1 3
2 4

樣例輸出

Q
D

樣例解釋

在第一組中,小\(Q\)選擇任意一個節點,分數為\(2\),小\(T\)選擇剩下兩個節點,分數為\(0\)

,小\(Q\)獲勝

在第二組中,小\(Q\)最好只能和小\(T\)平局,所以輸出\(D\)
資料範圍與提示

對於$30% \(的資料,\)n \leq 20$
對於\(100\%\)的資料,\(n \leq 100000\),\(w_i \leq 10^9\)

分析

一道不錯的思維題

首先我們考慮平局的情況

如果整棵樹上所有節點的異或和恰好為\(0\)的話

那麼無論先手選走哪一些點,後手選走的點一定與先手選走的點相同,這樣才能保證異或和為\(0\)

如果整棵樹上所有節點的異或和不為\(0\),那麼我們在二進位制位中會找到一個最高位的\(1\)

先手只要把這個\(1\)選走,那麼必定可以獲勝

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int a[maxn],n;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int tot=0;
        memset(a,0,sizeof(a));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            tot^=a[i];
        }
        for(int i=1;i<n;i++){
            int aa,bb;
            scanf("%d%d",&aa,&bb);
        }
        if(tot==0) printf("D\n");
        else printf("Q\n");
    }
    return 0;
}