题目链接: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。多解任意输出。
4 0 1 1 0
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"); }