E.Binary Cards(分治,贪心)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E.Binary Cards(分治,贪心)相关的知识,希望对你有一定的参考价值。

Link

考虑 2 a 2^a 2a最多被选择一次.如果选择两次 2 a , 2 a 2^a,2^a 2a,2a,明显是不如选 2 a , 2 a + 1 2^a,2^a+1 2a,2a+1优秀

那么知道这个以后,就会发现如果选择 2 a 2^a 2a,就不会再选 2 − a 2^-a 2a

因为 2 a , − 2 a 2^a,-2^a 2a,2a肯定是不如 2 a , − 2 a + 1 2^a,-2^a+1 2a,2a+1优秀的

这样我们就能得到对于一个 a a a,要么选择 2 a 2^a 2a,要么选择 2 − a 2^-a 2a

我们从 a = 0 a=0 a=0的情况开始考虑

如果存在数是奇数,显然 2 0 2^0 20 2 − 1 2^-1 21必选其一

如果都是偶数,那么没必要选,把所有数除以二进入一个相同的子问题

但是每次扫描判断是否有奇数,单次就是 O ( n ) O(n) O(n)的,而且还有那么多分治节点

但是注意到每次值域减小一半,意味着会有很多数字重复,那就排序去重可以降低复杂度

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
int n,a[maxn];
vector<int>nm;
vector<int> solve(int mx = 0)

    if( mx>19 ) return vector<int>(0);
    int ok = 0;
    for( int &x:nm )    if( x&1 )  ok = 1; break; 
    if( !ok )//不用加数字这一位
    
        for( int &x:nm )    x >>= 1;
        return solve( mx+1 );
    
    vector<int>temp = nm;
    for( int&x:nm ) if( x & 1 ) x = ( x + 1 ) >> 1; else x >>= 1;
    sort( nm.begin(),nm.end() );
    nm.erase( unique( nm.begin(),nm.end() ),nm.end() );
    vector<int>vec1 = solve( mx+1 );

    nm = temp;
    for(int&x:nm )  if( x & 1 ) x = ( x - 1 >> 1 ); else x >>= 1;
    nm.erase( unique( nm.begin(),nm.end() ),nm.end() );
    vector<int>vec2 = solve( mx+1 );
    vec1.push_back( -(1<<mx) ); vec2.push_back( 1<<mx );
    return vec1.size()<vec2.size()?vec1:vec2;

int main()

    cin >> n;
    for(int i=1;i<=n;i++)   cin >> a[i],nm.push_back( a[i] );
    vector<int> ans = solve();
    cout << ans.size() << endl;
    for(int v:ans ) cout << v << " ";


以上是关于E.Binary Cards(分治,贪心)的主要内容,如果未能解决你的问题,请参考以下文章

AtcoderD - Integer Cards 贪心

CF1172A Nauuo and Cards 贪心

分治、贪心五大算法

算法导论—分治法思想动态规划思想贪心思想

python_分治算法贪心算法动态规划算法

弄懂分治系列:换个模型,二分查找还会用吗?