zoukankan      html  css  js  c++  java
  • F. Make Them Similar ( 暴力折半枚举 + 小技巧 )

    传送门

    题意: 给你 n 个数 a[ 1 ]  ~ a[ n ], n <= 100; 让你找一个 x , 使得 a[ 1 ] = a[ 1 ] ^ x ~ a[ n ] = a[ n ] ^ x;

       且 a[ 1 ] ~ a[ n ] 的二进制位上的 1 的个数相等。  每个 a[ i ] <= 2^30;

    解: a[ i ] <= 2 ^ 30; 那么x也不会超过 2^30; 那我们暴力枚举两个 2 ^ 15;

        分别枚举 x 异或上 a[ i ] 的 低 15, 和 x 异或上 a[ i ] 的高15位;

        然后我们用 cnt[ 0 ][ 1 ]代表 a[ 1 ] 这个数 异或上你枚举的这个x后, 的低15位上 1 的个数。

        cnt[ 1 ][ 1 ] 代表 a[ 1 ] 这个数 异或上你枚举的 这个 x后, 的高 15 位上 1 的个数。

        那我们要找到一个 x,使得 cnt[ 0 ][ 1 ] + cnt[ 1 ][ 1 ]  = cnt[ 0 ][ 2 ] + cnt[ 1 ][ 2 ] = ...... = cnt[ 0 ][ n ] + cnt[ 1 ][ n ];

        那我们是 cnt[ 0 ] 和 cnt[ 1 ] 分开枚举的嘛。   

        那当我们枚举低15位时。我们就 开个 vector 存一下, cnt[ 0 ] 的 后一位减去前一位。 即  vector 存的是

        cnt[ 0 ][ 2 ] - cnt[ 0 ][ 1 ], cnt[ 0 ][ 3 ] - cnt[ 0 ][ 2 ]; ........ cnt[ 0 ][ n ] - cnt[ 0 ][ n - 1 ];

      那我们枚举高15位时。 我们的 vector 存的就是 -1 * cnt[ 1 ]的后一位减去前一位。 即

       -1 * (  cnt[ 1 ][ 2 ] - cnt[ 1 ][ 1 ] ) ........ -1 * (  cnt[ 1 ][ n ] - cnt[ 1 ][ n - 1 ]  );

      然后, 当 cnt[ 0 ] 的vector 和 cnt[ 1 ] 的vector 是一样的时候, 就意味着, 每个数的 cnt[ 0 ] + cnt[ 1 ] 是相等的。

      因为, cnt[ 0 ][ 2 ] - cnt[ 0 ][ 1 ] = -1 * (  cnt[ 1 ][ 2 ] - cnt[ 1 ][ 1 ]  ); 即

      cnt[ 0 ][ 2 ] + cnt[ 1 ][ 2 ] = cnt[ 0 ][ 1 ] + cnt[ 1 ][ 1 ];

      所以, 我们就找到 x 了, 我们开个 map, 存一下 每个 vector 对应的 状态 (statu);就行了。

    #include <bits/stdc++.h>
    #define LL long long
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define INF 0x3f3f3f3f
    #define inf 0x3f3f3f3f3f3f3f3f
    #define mem(i, j) memset(i, j, sizeof(i))
    #define pb push_back
    using namespace std;
    int ans = -1, n;
    map < vector< int >, int > mp;
    vector< int > Q;
    int a[105];
    void dfs1(int num, int statu) {
        if(num > 15) {
            Q.clear();
            for(int i = 1; i <= n; i++) {
                Q.push_back(__builtin_popcount((statu ^ a[i]) % (1 << 15)));
            }
            for(int i = 1; i < n; i++) {
                Q[i - 1] = Q[i] - Q[i - 1];
            }
            Q.pop_back();
            if(!mp[Q]) mp[Q] = statu;
            return ;
        }
        dfs1(num + 1, statu);
        dfs1(num + 1, statu | (1 << (num - 1)));
    }
    void dfs2(int num, int statu) {
        if(num > 15) {
            Q.clear();
            for(int i = 1; i <= n; i++) {
                ///__builtin_popcount(x) 用于计算x的二进制位上1的个数。
                Q.push_back(__builtin_popcount(statu ^ (a[i] >> 15)));
            }
            for(int i = 1; i < n; i++) {
                Q[i - 1] = -1 * (Q[i] - Q[i - 1]);
            }
            Q.pop_back(); /// 弹出最后一个元素。
            if(mp[Q]) {
                ans = mp[Q] | (statu << 15);
            }
            return ;
        }
        dfs2(num + 1, statu);
        dfs2(num + 1, statu | (1 << (num - 1)));
    }
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        dfs1(1, 0); dfs2(1, 0);
        printf("%d
    ", ans);
        return 0;
    }
    View Code

      

    一步一步,永不停息
  • 相关阅读:
    让WPF和SL控件同时支持绑定和赋值
    VS2010下如何调试Framework源代码(即FCL)
    使用Entity Framework和WCF Ria Services开发SilverLight之2:POCO
    WPF快速指导15:动画
    改善C#程序的建议5:引用类型赋值为null与加速垃圾回收
    使用Entity Framework和WCF Ria Services开发SilverLight之1:简单模型
    MVVM中的命令绑定及命令参数
    改善C#程序的建议7:正确停止线程
    Prism安装、MVVM基础概念及一个简单的样例
    改善C#程序的建议8:避免锁定不恰当的同步对象
  • 原文地址:https://www.cnblogs.com/Willems/p/11871019.html
Copyright © 2011-2022 走看看