M - XOR Almost Everything (^性质+DP搜索) (MINIEYE杯十六届)
题目swjtu—端午 - Virtual Judge (vjudge.net)
我的思路没有官方解那么巧妙,牢牢利用 ^ 的性质,
思路:
- 对 n-1个数 分别 ^ 某个值, 看能不能让他们都为0
- 利用 ^ 只对 二进制的每一位分别修改, 修改某一位 对其他位是没有影响的, 那么
- 就更具上面的性质 把 a[i],拆分成2进制的每一位
- 然后以 二进制每一位位单位看 整个数列, 比如 二进制第1位 , 对于 1,1 2,3 就是 1,1,0,1, 然后对n-1个数^ 2的n次方, 这里就是 2的0次方 1, 于是可以把他弄成0,0,0,0
- 看所有位数是不是都可以弄成0
- 问题来了, 对于 1,1,0,0 找n-1个数一直弄,是不是可以弄成0
- 小声bb:咋一看,一想,是找规律,找结论啊,于是我就苦苦的找,搞了很多规律弄上去,发现不对G
- 在回宿舍的路上,突然想到了,为什么不直接dp搜索一下,把说有情况弄出来呢,非要找什么规律!!!
- 于是dp一下, 因为n-1个数随便选嘛,就dp 1的个数就行了, 从0个开始 dp[0]=1;dfs一下就可以了
- 具体看代码

#include <bits/stdc++.h> using namespace std; #define ri register int #define M 100007 int n,m; long long p[M]; int num[M]; bool flag[M]; void dfs(int a) { flag[a]=1; int b=n-1; int tmp=b-a; if(flag[tmp]==0) { dfs(tmp); } tmp+=2; if(flag[tmp]==0&&tmp<=n) { dfs(tmp); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); //cout.tie(0); cin>>n; dfs(0); for(ri i=1;i<=n;i++) { cin>>p[i]; for(ri j=0;j<=31;j++) { long long a=1; if((a<<j)&p[i]) { num[j]++; } } } for(ri i=0;i<=31;i++) { if(flag[num[i]]==0) { printf("NO\n"); return 0; } } printf("YES"); return 0; }
简单说说: 官方解的思路 (有疑惑)
- 首先 可以对n-1个数^某个值,那么一定可以让他们弄成一样的数,就是 ^前缀和n的值
- 然后, 偶数个数,对于每一个值,可以^奇数个 ^前缀和n的值, 那么现在就有偶数个这个值,于是就是0
- 奇数个反之还是原数,就看他的^前缀和n的值 是不是0;
- 但是啊,我想不通,可不可以不把他们弄成一样,然后弄一下其他数让他们为0呢?