题意:给你三个整数a,b,k。找到两个满足一下条件的二进制数,x,y:
1 这两个二进制数每个都含有a个0和b个1.
2 x-y有且仅有k位1(只含1不含0)
限定条件,x和y都不能以0开头。
如果这两个二进制数存在,则输出Yes并输出这两个二进制数,否则输出No
思路:一开始想的是暴力搜索有多少种字符串,然后暴力求答案. 然后看官网题解,发现了一个很巧妙的构造方法:
以4 2 3 为例,k=3,则x-y的结果含且只含三位1,那么我们想,到底怎样两个二进制数相减,可以得到这种只含1的数呢?
观察样例发现,似乎只有在所有位都相同,相减时出现借位的情况时才满足。
我们把4,2的字符串中1排前列出来:
110000 串A
110000 串B
我们发现,首位的1是不能动的,串B的第二个1每向右移动以为,A-B的结果满足的k就+1,
将A和B再添加多个1和0进行普遍处理后:
1111000000 串A
1111000000 串B
我们发现,通过B最右边的1往右移动,其他的1不变,A串第二个1改为0(也可以不是第二个),就可以得到合理能满足的k,而且k的范围可以很轻松的判断:
当a!=0,b>=2时,0<=k<=a+b-2
对于a=0,b=1,k=0的情况我们进行一下特判, 就可以写出答案
思路是这样的,有一些小细节还没将清楚。。。
我的代码实现的不好,仅供参考
#include <bits/stdc++.h>
using namespace std;
int a,b,k;
/*
0123456
1111000
1011100
*/
int numa[200050];
/*
我们用这两个数组存储二进制数a和b
*/
int numb[200050];
void solve()
{
if(a==0||b==1)//特判a=0或b=1
{
if(k==0)
{
cout<<"Yes\n";
for(int i=0;i<b;i++)
cout<<"1";
for(int i=0;i<a;i++)
cout<<"0";
cout<<endl;
for(int i=0;i<b;i++)
cout<<"1";
for(int i=0;i<a;i++)
cout<<"0";
}
else cout<<"No\n";
return ;
}
if(k>a+b-2) //特判k是否能合理求得
{
cout<<"No\n"; return ;
}
cout<<"Yes\n";
int total=a+b;
/*
下面部分代码的用意是:
index=1是为了标记A串需要改为0的1的位置
index+k是为了标记B串中需要将0改为1的位置
*/
for(int i=0;i<b;i++)//将b个1先赋值在最前面,后面因为是全局数组所以自动为0
numa[i]=numb[i]=1;
int index=1;
while(index+k<b&&index<b)//这里有个
{
// 4 2 8
index++;
}
if(k!=0)//特判k==0
{
numb[index]=0;
numb[index+k]=1;
}
for(int i=0;i<total;i++)
cout<<numa[i];
cout<<endl;
for(int i=0;i<total;i++)
cout<<numb[i];
cout<<endl;
}
int main()
{
cin>>a>>b>>k;
solve();
}