F. Make Them Similar

题目链接:

题意:给出一个有n个数的数组a,问是否能找到一个x满足b[i]=a[i]^x。而这个b数组里面所有元素的二进制1的个数都是相等的

a[i]<(2^30)-1  

思路:

由数据范围可知,x的范围一定在2^30内,那么我们很容易想到meet in the middle !!!对于30位的搜索折半复杂度为2^15随随便便就能AC啦(硬是WA了4发,还写了巨长时间emmm)

首先我们预处理出前15位的状态,然后跟a数组全部元素做异或操作,那么对于15位后的我们可以取模去掉防止造成影响。

然后我们能得到当前状态异或前15位得到的每个新的元素的1的个数,那么我们统计一下后一位减当前位的差值(为什么这样我一会再说)

那么标记这个 vector数组,这个开个map就行了,顺便还能把当前状态放进去

那么之后就是枚举后15位了,同理我们能得到一个后15位的数组,对于这个数组我们用当前位减去后一位。

那么对于两个互补的数组,他们存在一个关系,一个用后一位减当前位,一个用当前位减后一位,得到的数组会是相同的。

证明其实也不难想:如果他们是互补的,那么他们的顺序一定是相反的。所以就有这个条件!!!

那么如果有满足这样的要求我们就可以得到答案了

详情请见代码!

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pb push_back
#define fi first
#define se second
const int N=2e6+10;
void read(int &a)
{
    a=0;int d=1;char ch;
    while(ch=getchar(),ch>'9'||ch<'0')
        if(ch=='-')
            d=-1;
    a=ch^48;
    while(ch=getchar(),ch>='0'&&ch<='9')
        a=(a<<3)+(a<<1)+(ch^48);
    a*=d;
}
int a[N],n;
vector <int> v;
map <vector <int>,int> vis;
int ans=-1;
void dfs1(int i,int now)
{
    if(i==15)
    {
        v.clear();
        for(re int j=1;j<=n;j++) v.pb(__builtin_popcount((now^a[j])%(1<<15)));
        for(re int j=1;j<n;j++) v[j-1]=v[j]-v[j-1];
        v.pop_back();
        if(!vis.count(v)) vis[v]=now;
        return;
    }
    dfs1(i+1,now);
    dfs1(i+1,now|(1<<i));
}
void dfs2(int i,int now)
{
    if(i==15)
    {
        v.clear();
        for(re int j=1;j<=n;j++) v.pb(__builtin_popcount(now^(a[j]>>15)));
        for(re int j=1;j<n;j++) v[j-1]-=v[j];
        v.pop_back();
        if(vis.count(v)) ans=vis[v]|(now<<15);
        return;
    }
    dfs2(i+1,now);
    dfs2(i+1,now|(1<<i));
}
int main()
{
    read(n);
    for(re int i=1;i<=n;i++) read(a[i]);
    dfs1(0,0);dfs2(0,0);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/acm1ruoji/p/11870284.html