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;
    
    
} 
View Code

简单说说: 官方解的思路 (有疑惑)

  • 首先 可以对n-1个数^某个值,那么一定可以让他们弄成一样的数,就是 ^前缀和n的值
  • 然后, 偶数个数,对于每一个值,可以^奇数个 ^前缀和n的值, 那么现在就有偶数个这个值,于是就是0
  • 奇数个反之还是原数,就看他的^前缀和n的值 是不是0;
  • 但是啊,我想不通,可不可以不把他们弄成一样,然后弄一下其他数让他们为0呢?
posted @ 2022-06-08 21:27  VxiaohuanV  阅读(56)  评论(0编辑  收藏  举报