import java.io.PrintStream; import java.util.Arrays; import java.util.Scanner; /** * Solution to Pieces of Parentheses * * @author vanb */ public class apiece_vanb { private static Scanner sc; private static PrintStream ps; /** * A Piece of the broken parentheses sign. * * @author vanb */ private class Piece implements Comparable { /** * open = number of mismatched open parens * close = number of mismatched close parens * net = net difference (open-close) * length = length of this string of parens */ public int open, close, net, length; /** * Create a Piece. * * @param open Number of mismatched open parens * @param close Number of mismatched close parens * @param length Length of this string of parens */ public Piece( int open, int close, int length ) { this.open = open; this.close = close; this.net = open-close; this.length = length; } @Override /** * Sort order. * * @param other Another Piece. * @return Standard for compareTo */ public int compareTo( Piece other ) { // The sort order is tricky. We've got to make sure that, as we add pieces left-to-right, // our balance is always positive. So, we've got to favor lost of opens and/or few closes. int diff; if( (net > 0) ^ (other.net > 0) ) { // If one net is positive and the other not, // then just use the difference in the nets. diff = other.net - net; } else if( net > 0 ) { // If both are positive (more opens than closes), // then favor fewer closes if you can. // If not, then just use the difference in net. if( close == other.close ) diff = other.net - net; else diff = close - other.close; } else { // If both are negative (more closes than opens), // then favor more opens if you can. // If not, then just use the difference in net. if( open == other.open ) diff = other.net - net; else diff = other.open - open; } return diff; } /** * A pretty String for debugging. */ public String toString() { return "[" + open + "," + close + "," + net + "," + length + "]"; } } /** * Do it! */ private void doit() { // Number of pieces int n = sc.nextInt(); // This will be the total length of all pieces cpombined. // That's the max string we could possibly produce. int total = 0; // Read in the pieces Piece pieces[] = new Piece[n]; for( int i=0; i0 ) --open; // A close matched an open else ++close; // An unmatched close } pieces[i] = new Piece( open, close, parens.length ); } // Sort the pieces to favor open parens Arrays.sort( pieces ); // This is a little tricky. // bestlength[i] is the longest string you can form with balance i. // The balance is the difference between the number of open parens and the number of close parens. // It's positive if there are more opens than closes, negative if more closes than opens, 0 if balanced. // So, when we're done, bestlength[0] will be our answer. // // This is why we sorted the pieces - to make sure that there are never more closes than opens. int bestlength[] = new int[total]; Arrays.fill( bestlength, -1 ); bestlength[0] = 0; for( Piece piece : pieces ) { // Remember, the balance number is the difference between opens and closes. // If this piece has n unmatched closes, then any case with a balance number less than n // won't have enough opens to match the closes. So, piece.close is a lower bound // on balance numbers we can consider. int lower = piece.close; if( piece.net<=0 ) { // If the net is negative, we can go forward through the balances. for( int i=lower; i=0 ) { int newbalance = i + piece.net; if( newbalance>=0 && newbalancebestlength[newbalance] ) { bestlength[newbalance] = bestlength[i]+piece.length; } } } else { // If the net is positive, then we can't go forward, we have to go backward. // because we'll modify a bestlength[] ahead of us, if we go forward, // we risk hitting a bestlength[] we've already modified, using the same piece more than once. for( int i=total-1; i>=lower; i-- ) if( bestlength[i]>=0 ) { int newbalance = i + piece.net; if( newbalance>=0 && newbalancebestlength[newbalance] ) { bestlength[newbalance] = bestlength[i]+piece.length; } } } } // Here's the answer. ps.println( bestlength[0] ); } /** * The Main! * * @param args Command-line args, unused. * @throws Exception */ public static void main( String[] args ) throws Exception { sc = new Scanner( System.in ); ps = System.out; new apiece_vanb().doit(); } }