codeforces#1257 F. Make Them Similar ( 经典中间相遇问题 )

题目链接:

http://codeforces.com/contest/1257/problem/F

题意:

给出$n$个30位整数

找到一个数,让它与这$n$个数分别异或,得到的$n$个数二进制1的个数相同

数据范围:

$1leq n leq 100$

分析: 

CF官方题解称这是中间相遇技巧

枚举答案的低15位,这时有$2^{15}$种情况

与给出的$n$个数的低15位去异或,得到1的数量定义为$low[i]$

把$(low[2]-low[1],low[3]-low[1],.....low[n]-low[1])$这个vector放入set

再枚举答案的高15位,得到$high[i]$数组

在set中寻找$(high[1]-high[2],high[1]-high[3],.....high[1]-high[1])$

AC代码:

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pcc pair<char,char>
using namespace std;
const int maxn=100+7;
const int maxm=(1<<15)+7;
struct Node{
    int ans;
    vector<int>ve;
    bool operator<(const Node &a)const{
        return ve<a.ve;
    }
}node;
set<Node>se;
int l[maxn],h[maxn];
int getlen[maxm],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        l[i]=(x&((1<<15)-1));
        h[i]=x>>15;
    }
    for(int i=0;i<maxm;i++){
        int v=i;
        while(v){
            if(v&1)getlen[i]++;
            v/=2;
        }
    }
    int len=(1<<15);
    for(int i=0;i<len;i++){
        node.ans=i;
        node.ve.clear();
        int v=getlen[i^l[1]];
        for(int j=2;j<=n;j++)
            node.ve.push_back(v-getlen[i^l[j]]);
        se.insert(node);
    }
    for(int i=0;i<len;i++){
        node.ans=i;
        node.ve.clear();
        int v=getlen[i^h[1]];
        for(int j=2;j<=n;j++)
            node.ve.push_back(getlen[i^h[j]]-v);
        if(se.find(node)!=se.end()){
            Node now=*se.find(node);
            printf("%d
",(i<<15)+now.ans);
            //if((i<<15)+now.ans==1073709057)return 0;
            return 0;
        }
    }
    printf("-1
");
    return 0;
}

  

原文地址:https://www.cnblogs.com/carcar/p/11865263.html