【算法】【二分】

0 阅读1分钟

Test Generator

题意简述
给定两个整数 ( s ) 和 ( m ),需要构造一个非负整数数组 ( a ),满足:

  1. 数组元素之和等于 ( s );
  2. 每个元素 ( a_i ) 的二进制位中,为 1 的位必须是 ( m ) 的二进制位中也为 1 的位(即 ( a_i & m = a_i ))。

要求判断是否存在这样的数组。若存在,输出数组的最小可能长度 ( n );否则输出 (-1)。

#include <bits/stdc++.h>  
using namespace std;  
using ll=long long;  
void so(){  
    ll s,m;cin>>s>>m;  
    ll ans=0;  
    int ok=0;  
    ll k=s;  
    for(int i=0;i<=62;i++){  
        if((m>>i)&1){  
            if(k%(1ll<<i)==0)ok=1;  
            break;  
        }//至少可以由最第低位构成  
    }if(ok==0){cout<<-1<<'\n';return;}  
    ll l=1,r=1e18;  
    while(l<=r){  
        ll mid=(l+r)/2;  
        s=k;  
        for(int i=62;i>=0;i--){  
            if((m>>i)&1){  
                ll d=min(mid,s/(1ll<<i));//优先用大的  
                //不可以超过mid次  
                s-=d*(1ll<<i);  
            }  
        }if(s>0){  
            l=mid+1;//不够再加  
        }else r=mid-1;  
        //最后l>r;  
        //当<=0,r去试更小的  
    }cout<<l<<'\n';  
}int main(){  
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  
    int t;cin>>t;  
    while(t--){so();}  
}

注意与启示

1.求最短的,可以想到二分

2.先不要看s,m有1的话s马上减,最多只能减mid(大的数先能用几次先用)