题目链接
CF1360H
解题思路
发现你可以十分高效的统计小于等于 \(x\) 的合法的数字数量。
并且你可以发现,当 \(x\) 递增时,合法的数字数量是不递减的,因此合法的数字数量是具有单调性的。
于是可以进行二分答案。
那么如何进行 check 呢?我们先将不可选用的二进制数字给转化成数字,然后假设我们是找小于 \(x\) 可选用的数字数量,直接用 \(x + 1\) 再减去小于等于 \(x\) 的不可选用的数字数量即可。
因此单次 check 根据是 \(O(n)\) 的。
总时间复杂度为 \(O(n \log 2^m)\),非常优秀。
注意输出的时候需要带前导零补齐输出。
参考代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
//#define map unordered_map
#define re register
#define ll long long
#define forl(i,a,b) for(re ll i=a;i<=b;i++)
#define forr(i,a,b) for(re ll i=a;i>=b;i--)
#define forll(i,a,b,c) for(re ll i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(re ll i=a;i>=b;i-=c)
#define pii pair<ll,ll>
#define mid ((l+r)>>1)
#define lowbit(x) (x&-x)
#define pb push_back
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
ll _t_;
void _clear(){}
ll L,R;
ll n,m;
ll a[110];
string s;
ll pw(ll x){return 1ll<<x;
}
ll f(string s)
{ll k=0,sum=0;reverse(s.begin(),s.end());for(auto i:s)sum+=pw(k++)*(i=='1');return sum;
}
bool check(ll x)
{ll sum=x+1; // 注意 0 forl(i,1,n)if(a[i]<=x)sum--;
/// if(x==4)
// cout<<"???"<<sum<<endl;return sum<((pw(m)-n+1)/2);
}
void print(ll x)
{if(x==0){forl(i,1,m)cout<<0;cout<<endl;return ;}string s="";while(x)s+=x%2+'0',x/=2;ll sz=s.size();forl(i,1,m-sz)s+='0';reverse(s.begin(),s.end());cout<<s<<endl;
}
void solve()
{_clear();cin>>n>>m;L=0,R=pw(m)-1;forl(i,1,n)cin>>s,a[i]=f(s);sort(a+1,a+1+n);while(L<R){ll Mid=(L+R)/2;if(check(Mid))L=Mid+1;elseR=Mid;}print(L);
// cout<<L<<endl;
}
int main()
{IOS;_t_=1;cin>>_t_;while(_t_--)solve();QwQ;
}