1. 程式人生 > >Codeforces 949E Binary Cards

Codeforces 949E Binary Cards

contest 復雜 ons break 是我 ++ n) include ORC

Description

給出一個長度為 \(n\) 的數組,求使得用最少數量的 \(2^k\)\(-2^k\) 的數,使得數組中的每一個元素都可以被你選出的 \(2\) 的次冪表示
題面

Solution

註意到兩個性質:
1.一個數不會用兩次,舉個例子:用兩個 \(2\),不如用 \(2,4\) 範圍廣
2.一個數不會既用 \(2^k\) 又用 \(-2^k\),顯然用 \(-2^k,2^{k+1}\) 或者 \(2^k,-2^{k+1}\) 更優

這樣就可以依次考慮每一位了:
如果所有的數都不含有這一位,那麽就直接把所有的數除以 \(2\)
如果存在數含有這一位,那麽用 \(-2^k\)

或者 \(2^k\) 把含有這一位的數都給去掉,然後再把所有的數除以 \(2\)
對於第二種情況我們直接搜索一下就好了

這樣復雜度有些問題,但是我們把數去重之後,第 \(k\) 層的數就最多只有 \(\frac{max(A[i])}{2^{k}}\)
復雜度就變成了分治的復雜度了

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[21][N],top=0,st[N],ans[N],anslen=N;
inline void dfs(int t,int n){
    if(t>20 || top>=anslen)return ;
    if(n==1 && !b[t][1]){
        if(top<anslen){
            anslen=top;
            for(int i=1;i<=top;i++)ans[i]=st[i];
        }
        return ;
    }
    bool flag=1;
    for(int i=1;i<=n;i++)if(b[t][i]&1){flag=0;break;}
    if(flag){
        for(int i=1;i<=n;i++)b[t+1][i]=b[t][i]>>1;
        n=unique(b[t+1]+1,b[t+1]+n+1)-b[t+1]-1;
        dfs(t+1,n);
        return ;
    }
    for(int w=-1;w<=1;w+=2){
        for(int i=1;i<=n;i++)
            if(b[t][i]&1)b[t+1][i]=(b[t][i]+w)>>1;
            else b[t+1][i]=b[t][i]>>1;
        st[++top]=-w*(1<<t);
        int tmp=unique(b[t+1]+1,b[t+1]+n+1)-b[t+1]-1;
        dfs(t+1,tmp);
        top--;
    }
}
int main()
{
    freopen("pp.in","r",stdin);
    freopen("pp.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    n=unique(a+1,a+n+1)-a-1;
    for(int i=1;i<=n;i++)b[0][i]=a[i];
    dfs(0,n);
    printf("%d\n",anslen);
    for(int i=1;i<=anslen;i++)printf("%d ",ans[i]);
    return 0;
}

Codeforces 949E Binary Cards