NOIP 模拟5 T3 big

题面:你需要在[0,2^n)中选一个整数 x,接着把 x 依次异或 m 个整数a1~am
     在你选出 x 后,你的对手需要选择恰好一个时刻(刚选完数时、异或一些数后或是最后),将 x 变为NOIP 模拟5 T3 big你想使 x 最后尽量大,而你的对手会使 x 最后尽量小。
     你需要求出 x 最后的最大值,以及得到最大值的初值数量

     对于 20%的数据,n<=10,m<=100。
     对于 40%的数据,n<=10,m<=1000。
     对于另外 20%的数据,n<=30,m<=10。
     对于 100%的数据 n<=30,m<=100000,0<=ai<2^n。

考场上拿到这道题是很懵的 问题在于对于异或的理解应用 实质上是对于一些基础性问题的理解并不深入

  分析问题 值得注意的是 NOIP 模拟5 T3 big 我们很显然需要理解这个式子在说什么

观察式子结构 应该能明确用二进制视角剖析 因此很简单 2X表示X左移一位 2^n表示X右移n位 综合来说就是将X首位放到了末尾

显然模2^n的结果不变 而2X模2^n相当与左移一位后删除首位 配合上述,我们可以得出结论 原式实际上是对X的逻辑左移

  继续考虑 为了将结论应用到解题中 我们显然要分析原式与异或运算体系的关联

异或运算的一个重要特点是位与位之间的运算是相互独立的互补影响 由此很容易推出a ^ (b << 1) = (a << 1) ^ b (其中<<代表逻辑左移)

  接下来思路就很清晰l 因为同时考虑x的选择和左移十分复杂 因此我们转而考虑a[]的左移 可以预处理出a[]的前缀和(逻辑左移)与后缀和

目标是最大异或和 显然这是一道Trie树模板题 存储0,1字符串进行抉择

  值得一提的是“而你的对手会使 x 最后尽量小”这就是说同时存在0,1两种选择则无法对结果造成贡献

若仅存在一种选择 则取反进行选择 代码用dfs深搜枚举可能情况即可

 

NOIP 模拟5 T3 big
 1 #include<bits/stdc++.h>    
 2 using namespace std;            
 3 #define I int
 4 #define C char
 5 #define RE register
 6 #define V void
 7 #define L inline                                  
 8 const I MAXM =  100050;
 9 I n,m,mod,num,res,swr,tot,a[MAXM],qa[MAXM],ha[MAXM],trie[MAXM << 5][2],l[MAXM << 5],r[MAXM << 5];
10 L I read(); L I fir(I); L V ins(I); V dfs(I,I); 
11 signed main(){
12     n = read(); m = read(); mod = 1 << n;
13     for(RE I i(1);i <= m; ++ i) a[i] = read();
14     for(RE I i(1);i <= m; ++ i) qa[i] = qa[i - 1] ^ fir(a[i]);
15     for(RE I i(m); i ; -- i)      ha[i] = ha[i + 1] ^ a[i];
16     for(RE I i(0);i <= m; ++ i) ins(qa[i] ^ ha[i + 1]);
17     dfs(0,n - 1);    
18     printf("%d\n%d",res,num);       
19 }
20 L I read(){  RE I x(0);RE C z = getchar(); while(!isdigit(z)) z = getchar(); while(isdigit(z)) x = (x << 3) + (x << 1) + (z ^ 48),z = getchar(); return x;  }
21 L I fir(I a){  return ((a >> n - 1) | (a << 1)) % mod;  }
22 L V ins(I a){   I p(0);
23     for(RE I i(n - 1),t;i >= 0; -- i){
24         t = a >> i & 1;
25         if(!trie[p][t]) trie[p][t] = ++tot,t ? l[p] = tot : r[p] = tot;
26         p = trie[p][t];
27     }
28 }
29 V dfs(I from,I t){
30     if(!trie[from][1] && !trie[from][0]){
31       if(swr == res)    num++;
32         if(swr > res)   res = swr,num = 1;
33     }
34     if(trie[from][1] && !trie[from][0])     swr |= 1 << t,dfs(l[from],t - 1),swr ^= 1 << t;
35     if(!trie[from][1] && trie[from][0])     swr |= 1 << t,dfs(r[from],t - 1),swr ^= 1 << t;
36     if(trie[from][1] && trie[from][0])      dfs(l[from],t - 1),dfs(r[from],t - 1);
37 }
View Code

 

上一篇:分块


下一篇:5.最长回文子串