import java.io.*; import java.util.*; import java.math.*; /** * Solution to Alchemy * * We will organize the circles in a forest of trees, where each circle's parent * is the smallest circle which contains that circle. We'll then do all of our work with * tree traversals. * * @author vanb */ public class alchemy_vanb { public Scanner sc; public PrintStream ps; public int n; public Circle circles[]; /** * A Circle. * * @author vanb */ public class Circle implements Comparable { /** Center and Radius */ public int x, y, r; /** a and b transition costs, and order number */ public int a, b, index; /** Count of ancestors */ public int count=0; /** * The minimum number of ancestors which must be drawn after and around * this circle for it to achieve its maximum score */ public int minparents=0; /** The best score possible for this circle */ public long bestscore=0L; /** * scores[i] is the score for this circle if exactly i ancestors * are drawn after and around it. */ public long scores[]; /** The smallest circle which is around this one */ public Circle parent; /** Is this circle a candidate to be drawn? */ boolean candidate; /** Has this circle already been drawn? */ public boolean chosen; /** * A list if the circles which are inside this circle * but not inside any other circle which is inside this circle. */ LinkedList kids = new LinkedList(); /** * Create a circle * @param x X coord of center * @param y Y coord of center * @param r Radius * @param a Fire->Water transition * @param b Water->Fire transition * @param index Order */ public Circle( int x, int y, int r, int a, int b, int index ) { this.x = x; this.y = y; this.r = r; this.a = a; this.b = b; this.index = index; parent = null; } @Override /** * Compare this circle to another circle by radius. * * @param c Another circle * @return <0 if this circle is smaller than c, 0 if same, >0 if bigger */ public int compareTo( Circle c ) { return r - c.r; } /** * Find the best score (and a few other things) for this circle * via a traversal. * * @param nancestors Number of ancestors of this circle * @return The best possible score for the subtree rooted at this circle */ public long findbests( int nancestors ) { scores = new long[nancestors+1]; scores[0] = 0; for( int i=1; i<=nancestors; i++ ) { // Compute the score for i ancestors drawn after and around this circle scores[i] = scores[i-1] + (((i&1)==1) ? a : b); if( scores[i]>bestscore ) { // If this is the best, remember it, // and remember the minimum number of ancestors bestscore = scores[i]; minparents = i; } } // Remember the number of ancestors count = nancestors; // Compute and return the total best score for this subtree long total = bestscore; for( Circle kid : kids ) total += kid.findbests( nancestors+1 ); return total; } /** * Mark candidate nodes. * * @param before The number of ancestor circles already drawn before this one. * @return true if it's OK to choose an ancestor of this one, otherwise false */ public boolean choose( int before ) { candidate = false; boolean ancestorsok = true; if( !chosen ) { // This is the number of ancestors of this circle which have yet to be drawn. // If we draw this circle now, this is the number of circles which will get drawn around it. int after = count-before; // It's a candidate if this score is its best score candidate = (scores[after]==bestscore); // Remember that minparents is the minimum number of ancestors this // circle needs to get its max score. // If there's more than that available, we're OK. // If not, we've got to draw this circle before any of its ancestors // to get the max score, so drawing ancestors is NOT OK. ancestorsok = (after>minparents); } else ++before; // Check to see if any descendants need for this circle to wait to be drawn boolean kidsok = true; for( Circle kid : kids ) kidsok &= kid.choose( before ); candidate &= kidsok; // Pass the OKs up the tree return kidsok && ancestorsok; } /** * A pretty String for debugging. * * @return A pretty String for debugging. */ public String toString() { return "{x=" + x + ", y=" + y + ", r=" + r + ", a=" + a + ", b=" + b + "}"; } } /** * Driver. * @throws Exception */ public void doit() throws Exception { sc = new Scanner( System.in ); ps = System.out; int n = sc.nextInt(); circles = new Circle[n]; // Read and create the circles for( int i=0; iMath.abs(c1.r-c2.r)) // { // System.err.println( "PANIC!! circles intersect!" ); // } // } // Find the best possible score, and set up bestscore, scores[], minparents // It's a traversal, so only call it on the roots // (i.e. nodes with no parents) long score = 0L; for( Circle c : circles ) if( c.parent==null ) score += c.findbests( 0 ); ps.println( score ); // Now, the ordering... boolean first = true; for( int i=0; i