[构造]CF550E Brackets in Implications

题目链接:http://codeforces.com/problemset/problem/550/E

题意:定义一种逻辑运算符“->”,左到右结合,真值表如下。

0 -> 0 = 1

0 -> 1 = 1

1 -> 0 = 0

1 -> 1 = 1

给一个n,再输入长度为n的01串,求一种加括号的方法让最后值为0,可以就输出YES和加括号的方法,输出格式如样例,否则输出NO。多解任意输出。

input
4
0 1 1 0
output
YES
(((0)->1)->(1->0))

看真值表,只有1->0可以得到0。

也就是说任何值去结合1  像这样((X X …) 1 )  的值是1,0去结合任何值  像这样( 0 (X  X …))  的值是1。

如果n是1,那么s[0]必须是0,否则输出NO。

在n不是1的基础上,最后一位s[n-1]一定是0,否则输出NO。

在s[n-1]是0的基础上,如果倒数第二位s[n-2]是1,那么直接输出YES,因为1前面的任何值结合1都是1,1再结合0就是0,直接输出不用加括号。

在s[n-1]是0的基础上,如果s[n-2]是0,要有解的话,需要让s[n-2]凑成1。

那么需要再找一个0,构造方法如下。

x x x x (0 (x x x x x x x 0) ) 0

(0(x x x x x x x 0)) 这一部分永远是1 因为 第一个0结合后面的任何值都是1,那么括号算完之后就回到了s[n-2]是1的情况了。

如果没有找到第三个0,就输出NO。

嗯,想清楚构造方法很是很简单的,就怕比赛的时候想不清楚。

很少做构造的题,贴个代码。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int s[100005];
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) scanf("%d", &s[i]);

    if(n==1){ //n为1
        if(s[0]==0) printf("YES\n0\n");
        else puts( "NO" );
        return 0;
    }
    if(s[n-1]==1){// 末位不为0
        puts( "NO" );
        return 0;
    }
    if(s[n-2]==1){ //倒数第二位是1
        puts( "YES" );
        for(int i = 0; i < n - 2 ; ++i) printf("%d->", s[i]);
        printf("1->0\n");
        return 0;
    }

    int cnt = n -2, zero = -1; //倒数第二位不是1 需要构造
    for(int i = n-3 ; i>=0&&zero==-1; --i)
        if(s[i] == 0) zero = i;
    if(zero == -1) {
        puts( "NO" );
        return 0;
    }
    puts( "YES" );
    for(int i = 0 ; i < zero ; ++i) printf("%d->", s[i]);
    printf("(0->(");
    for(int i = zero + 1; i<cnt; ++i) printf("%d->", s[i]);
    printf("0))->0");
}


你可能感兴趣的:(ACM,codeforces,构造)