CSU 1213 字典树
1323: ZZY and his little friends
Time Limit: 5 Sec Memory Limit: 256 MBSubmit: 158 Solved: 79
[Submit][Status][Web Board]
Description
zzy养了一只小怪兽和N只凹凸曼,单挑的话每只凹凸曼都不是小怪兽的对手,所以必须由两只凹凸曼合作来和小怪兽战斗。凹凸曼A和凹凸曼B合作的战斗力为他们战斗力的异或值。现在由zzy从N只凹凸曼中选出两只来和小怪兽战斗。请问zzy能否选出两只凹凸曼使他们能够战胜小怪兽(他们的战斗力比小怪兽大)。
Input
输入有多个例子,直到文件结束。 每个例子的第一行含两个数N和M,表示有N(2<=N<=100000)只凹凸曼,小怪兽的战斗力为M(0<M<=1000000000)。接着有一行N个数,每个数Ai(0<Ai<M)表示每只凹凸曼的战斗力。
Output
对于每个例子输出一行,如果能选出两只凹凸曼使他们战胜小怪兽输出"YES", 否则输出"NO"(不含引号)
Sample Input
2 5 1 1 2 6 5 2
Sample Output
NO YES
题意:给定一个长度为n的序列,问能否在里面找两个数,使得它们的抑或值大于给定的数m、
解题思路:由于n很大,不可能枚举任意两个数的抑或值,以此可以考虑建立一颗字典树,从高位到低位,对于第i个数,在字典树里查找前i-1个数与它的抑或值,对于每一位,字典树总是朝着相反的方向跑,查到就break,否则把当前的数插入字典树中。
代码:
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<string> #include<queue> using namespace std; const int maxn=100010; int ch[40*maxn][2],root,used,v[maxn]; void add(int x) { int s=root; for(int i=31;i>=0;i--) { int p=(x>>i)&1; if(!ch[s][p])ch[s][p]=++used,memset(ch[used],0,sizeof(ch[0])); s=ch[s][p]; } } int query(int x) { int s=root; int ans=0; for(int i=31;i>=0;i--) { int p=(x>>i)&1; if(p) { if(ch[s][0])ans|=(1<<i),s=ch[s][0]; else s=ch[s][1]; } else { if(ch[s][1])ans|=(1<<i),s=ch[s][1]; else s=ch[s][0]; } } return ans; } int main() { int i,j,k,m,n; while(~scanf("%d%d",&n,&m)) { for(i=1;i<=n;i++)scanf("%d",&v[i]); used=root=1;memset(ch[1],0,sizeof(ch[1])); add(v[1]); int ok=0; for(i=2;i<=n&&!ok;i++) { k=query(v[i]); if(k>m){ok=1;break;} add(v[i]); } if(ok)puts("YES"); else puts("NO"); } return 0; }

浙公网安备 33010602011771号