标签:bool int limit 说明 区间 cti long tor string
Time limit per test: 2 seconds
Memory limit per test: 256 megabytes
Consider all binary strings of length m (1≤m≤60). A binary string is a string that consists of the characters 0 and 1 only. For example, 0110 is a binary string, and 012aba is not. Obviously, there are exactly 2m such strings in total.
The string s is lexicographically smaller than the string t (both have the same length m) if in the first position i from the left in which they differ, we have s[i]<t[i]. This is exactly the way strings are compared in dictionaries and in most modern programming languages when comparing them in a standard way. For example, the string 01011 is lexicographically smaller than the string 01100, because the first two characters are the same, and the third character in the first string is less than that in the second.
We remove from this set n (1≤n≤min(2m?1,100)) distinct binary strings a1,a2,…,an, each of length m. Thus, the set will have k=2m?n strings. Sort all strings of the resulting set in lexicographical ascending order (as in the dictionary).
We number all the strings after sorting from **0 **to k?1. Print the string whose index is ?(k?1)/2? (such an element is called median), where ?x? is the rounding of the number down to the nearest integer.
For example, if n=3, m=3 and a=[010, 111, 001], then after removing the strings ai and sorting, the result will take the form: [000, 011, 100, 101, 110]. Thus, the desired median is 100.
The first line contains an integer t (1≤t≤1000) — the number of test cases. Then, t test cases follow.
The first line of each test case contains integers n (1≤n≤min(2m?1,100)) and m (1≤m≤60), where n is the number of strings to remove, and m is the length of binary strings. The next n lines contain a1,a2,…,an — distinct binary strings of length m.
The total length of all given binary strings in all test cases in one test does not exceed 105.
Print t answers to the test cases. For each test case, print a string of length m — the median of the sorted sequence of remaining strings in the corresponding test case.
5
3 3
010
001
111
4 3
000
111
100
011
1 1
1
1 1
0
3 2
00
01
10
100
010
0
1
11
The first test case is explained in the statement.
In the second test case, the result after removing strings and sorting is [001, 010, 101, 110]. Therefore, the desired median is 010.
长度为 m 的二进制字符串共有 2m 个
从中删除 n 个字符串,再按照字典序排序
问剩余的字符串中排在最中间的字符串是什么
如果编号取 0 ~ k-1 ,则最中间的编号是 (k-1)/2 向下取整
因为长度最大为 60 ,所以可以将二进制字符串转成长整型进行处理
将输入的所有待删除的数字用 vector 存起来并排序
因为剩余的字符串有 2m-n 个
所以最中间的字符串编号为 (2m-n-1)/2
从 “某个数字在所有存在的数字中排第几” 的角度入手
因为已经求出最中间的字符串编号,所以在可行范围内满足二分查找的性质
所以只要在 0 ~ 2m-1 中二分查找答案即可
每次判断 mid 时,在vector中再二分找出 mid 之前有多少已经删去的数字
再用 mid-已经删去的个数 <= 最中间的字符串编号
的真假性维护二分区间即可
Ps.
考虑到可能二分到已经删除的数字
如果真正的答案比其小,那么由于 mid 取到的会较大,导致判断时 "mid-已经删去的个数" 会较大,返回false,所以二分区间还是会左移
如果真正的答案比其大,那么由于 mid 取到的会较小,导致判断时 "mid-已经删去的个数" 会较小,返回true,所以二分区间还是会右移
所以这里不构成影响,二分时使用 lower_bound 即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<ll> v;
int n,m;
ll k;
bool check(ll mid)
{
int p=lower_bound(v.begin(),v.end(),mid)-v.begin(); //先二分搜索出前面有多少已经删去的数字
return mid-p<=k; //减去后再判断
}
void solve()
{
string str;
ll l=0,r=1,mid;
v.clear();
cin>>n>>m;
for(int i=1;i<=m;i++)
r*=2LL;
k=(r-n-1)/2; //表示最中间的数字的编号
r--;
for(int i=1;i<=n;i++)
{
cin>>str;
ll d=0;
for(char c:str) //二进制转成数字
{
d*=2LL;
if(c==‘1‘)
d++;
}
v.push_back(d);
}
sort(v.begin(),v.end());
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) //返回true时,说明mid可能过小也可能就是答案
l=mid+1;
else //false说明mid过大,一定不是答案
r=mid-1;
}
string ans(m,‘0‘);
for(int i=m-1;i>=0;i--) //将r转成二进制,固定长度为m
{
ans[i]=‘0‘+(r%2);
r/=2;
}
cout<<ans<<‘\n‘;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
solve();
return 0;
}
Codeforces 1360H - Binary Median (二分)
标签:bool int limit 说明 区间 cti long tor string
原文地址:https://www.cnblogs.com/stelayuri/p/12955883.html