CF 709D 数学,构造

解析一道关于构造特定01序列的算法题,通过给定的四种二元组数量来构建符合要求的序列,讨论了解题思路及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Recover the String
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
For each string s consisting of characters ‘0’ and ‘1’ one can define four integers a00, a01, a10 and a11, where axy is the number of subsequences of length 2 of the string s equal to the sequence {x, y}.

In these problem you are given four integers a00, a01, a10, a11 and have to find any non-empty string s that matches them, or determine that there is no such string. One can prove that if at least one answer exists, there exists an answer of length no more than 1 000 000.

Input
The only line of the input contains four non-negative integers a00, a01, a10 and a11. Each of them doesn’t exceed 109.

Output
If there exists a non-empty string that matches four integers from the input, print it in the only line of the output. Otherwise, print “Impossible”. The length of your answer must not exceed 1 000 000.

Examples
input
1 2 3 4
output
Impossible
input
1 2 2 1
output
0110
题意:给了 a00 a01 a10 a11四个数,构造一个01序列。a00表示满足pi==0,pj==0且j>i的二元组数量。其余3个同理。若无合法的序列输出Impossible。

做法:显然cnt0(cnt0-1)/2=a00,cnt1(cnt1-1)/2=a11。用二次方程求根公式求出cnt0和cnt1,若无根则无解。然后判断a01+a10==cnt0*cnt1是否成立,不成立则无解,成立则必有解。

几个坑点:对于0 0 0 0,0 0 0 x,x 0 0 0 单独判一下。最重要的是求根公式里的8a00(a11)会爆
int!!!尼玛啊!!!好好的上分场就这么gg了不服啊!!!改了秒过啊!!!

cnt0*cnt1就是所有01对(不分顺序)的个数。
构造的过程很自然,先把0全放在左边,这样所有01对都是(01)的形式,每把一个0从左边移到最右边就是(10)加了cnt1的个数。做一个带余除法,余数用1个0在所有的1中间微调即可。

举个例子具体一点说:
10 18 7 10
0000011111->0000111110->0001101110

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a00, a01, a10, a11;
int cnt0, cnt1;
int main()
{
    scanf("%d%d%d%d", &a00, &a01, &a10, &a11);
    if(!a00&&!a01&&!a10&&!a11){
        printf("0\n");
        return 0;
    }
    if(!a00&&!a01&&!a10)
    {
        cnt1=(sqrt(8*(ll)a11+1)+1)/2+0.000001;
        if((ll)cnt1*(cnt1-1)/2!=a11){
        printf("Impossible\n");
        return 0;
        }
        for(int i=1;i<=cnt1;i++)printf("1");
        printf("\n");
        return 0;
    }
    if(!a11&&!a01&&!a10)
    {
        cnt0=(sqrt(8*(ll)a00+1)+1)/2+0.0000001;
        if((ll)cnt0*(cnt0-1)/2!=a00){
        printf("Impossible\n");
        return 0;
        }
        for(int i=1;i<=cnt0;i++)printf("0");
        printf("\n");
        return 0;
    }


    cnt0=(sqrt(8*(ll)a00+1)+1)/2+0.0000001;
    if((ll)cnt0*(cnt0-1)/2!=a00){
        printf("Impossible\n");
        return 0;
    }
    cnt1=(sqrt(8*(ll)a11+1)+1)/2+0.0000001;
    if((ll)cnt1*(cnt1-1)/2!=a11){
        printf("Impossible\n");
        return 0;
    }
    //printf("%d %d\n", cnt0, cnt1);
    if(ll(cnt1)*ll(cnt0)!=ll(a01)+ll(a10)){
        printf("Impossible\n");
        return 0;
    }
    int tot=a01+a10;
    int pp=a01/cnt1;
    int qq=a01-pp*cnt1;
    for(int i=1;i<=pp;i++)printf("0");
    for(int i=1;i<=cnt1-qq;i++)printf("1");
    if(pp<cnt0)printf("0");
    for(int i=1;i<=qq;i++)printf("1");
    for(int i=1;i<=cnt0-pp-1;i++)printf("0");
    printf("\n");
}

最近各种zz实习烦的一笔,搞得智商低下,还是要多做比赛挽回一点。cf打到1800停住了,也正常,div2abc上d1不现实(虽说手速犇能做到)。但是感觉突破也快到了,毕竟div2的d不难,只是由于各种zz原因(比如这次的爆int和之前的fst)跪了。预计3场以内上紫吧,但愿别打脸。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值