Codeforces 1492D、Genius's Gambit

原题网址

https://codeforces.com/contest/1492/problem/D

题目大意

给定a,b,k,求x,y使得x和y的二进制表示都恰有a个0和b个1,且不能使用开头的0。另外,还要求x-y的二进制表示恰有k个1。如果不存在x,y输出No,否则输出x和y的二进制表示。

解题思路

此题为构造性问题。

注意到10000-00001=01111(1个1和p个0生成p个1),11110-01111=01111(1个0和p个1生成p个1),我们可以解决该题。

首先若k=0,肯定有解,只要x和y相等即可。

k>0时,若没有0或只有1个及以下的1,肯定无解。因为x和y开头必须是1,剩下的里面必须0和1都有才可能有解。

k>0,有1个以上1且有0时,考虑x=11110000和y=11100010。首先,x把1都放前面,0都放后面;y在x基础上把最右侧1往右移动位置。这样每移动一位,x-y就会多出一个1。最多得到a个1。即k<=a时有解。

若k>a,则最后一个1已经无处可移动了,得到x=11110000和y=11100001。我们还能把最左侧0往左移动位置。这样每移动一位,x-y还会再多出一个1。因为最高位的1不能越过,还有一个1已经在最低位了,这样最多移动b-2次。所以k<=a+b-2时有解。

其他情况无解。

一般情况下想到的都是多少个1后面放多少个0这种直接构造解的方法。但是这题用先构造一个特殊解,然后交换适当位置得到新解的方法更方便。

我的代码

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a, b, k;
    string x, y;
    ios::sync_with_stdio(false);
    cin >> a >> b >> k;
    if (k > 0 && (a == 0 || b == 1)) {
        cout << "No\n";
        return 0;
    }
    for (int i = 0; i < b; ++i) {
        x.push_back('1');
        y.push_back('1');
    }
    for (int i = 0; i < a; ++i) {
        x.push_back('0');
        y.push_back('0');
    }
    if (k <= a) {
        swap(y[b - 1], y[k + b - 1]);
        cout << "Yes\n" << x << endl << y;
        return 0;
    }
    if (k <= a + b - 2) {
        swap(y[b - 1], y[a + b - 1]);
        swap(y[b - 1], y[b - 1 - (k - a)]);
        cout << "Yes\n" << x << endl << y;
        return 0;
    }
    cout << "No\n";
    return 0;
}
posted @ 2021-04-09 21:20  capacito  阅读(43)  评论(0编辑  收藏  举报