+ All Categories
Home > Documents > David Van Brackle Chief Judge, Southeast USA Region, ICPC.

David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Date post: 17-Dec-2015
Category:
Upload: rosalind-lawson
View: 217 times
Download: 0 times
Share this document with a friend
Popular Tags:
31
David Van Brackle Chief Judge, Southeast USA Region, ICPC
Transcript
Page 1: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

David Van BrackleChief Judge, Southeast USA Region, ICPC

Page 2: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Problem Division

Candy Store I & II

Collision Detection I & II

Component Testing I

Do It Wrong, Get It Right I & II

Dueling Philosophers II

Funhouse I

A Terribly Grimm Problem I

Heads or Tails I

Paint Me II

Party Games II

Reverse Nonogram II

Tsunami I & II

Unhappy Numbers I & II

Walls I & II

Page 3: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

1D Dynamic Programming on Pennies best[i] is the most calories you can buy with i pennies

maxcal = 0For i = 0 to max dollars by penny

For each type of candy jtotalcost = i + cost[j]totalcal = best[i] + cals[j]If totalcost<=max and totalcal > best[totalcost]

best[totalcost] = totalcalIf totalcal > maxcal

maxcal = totalcalEnd If

End IfEnd For

End For

One thing to look out for – the max calories may not occur at the max cost!

Page 4: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Have to simulate this one Some useful physics formulas:

Let the inputs per car be [t0,x0,y0,v0] and [t1,x1,y1,v1] Acceleration: a=(v1-v0)/(t1-t0)Velocity: v(t)=a*(t-t1) + v1

Angle of movement:Θ=atan2( y1-y0, x1-x0)Acceleration x-y: ax=a*cos(Θ), ay=a*sin(Θ)Velocity x-y: vx1=v1*cos(Θ), vy1=v1*sin(Θ) Position accel: pax(t)=½*ax*(t-t1)2 + vx1*(t-t1)

pay(t)=½*ay*(t-t1)2 + vy1*(t-t1)Terminal Velocity: If a<0, vT=0 If a>0, vT = 80

vxT=vT*cos(Θ), vyT=vT*sin(Θ)Time of freeze: solve v(t)=vT for t

tT=(vT + a*t1 – v1) / a [if a=0, tT=+infinity]Position of freeze: xT=pax(tT), yT=pay(tT)Position: px(t) = If t<tT then pax(t) else xT+vxT*(t-tT)

py(t) = If t<tT then pay(t) else yT+vyT*(t-tT)

Now, just iterate from the max time to the max time + 30 seconds by some small time increment. Compute positions and distance, and see if they’re ever closer than 18.

Page 5: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Envision as a max flow graph:

Source

Engineers Components

Sink

Source linked to every engineer.

Weight = # of components that engineer can test

Every Component linked to Sink. Weight = # of tests that component needs

Every Engineer linked to every Component. Weight = 1

Of course, since there can be 109 engineers and 109 components, this is too big for Ford/Fulkerson

Page 6: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

But Max Flow is the same as Min Cut. Look at it as a Min Cut problem.

Source

Engineers Components

Sink

Start by putting all of the SourceEngineer edges in the cut. The cost of this cut is the sum of all jobs for all engineers.

Page 7: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Now, try to take a SourceEngineer edge out of the cut and put it back in the graph.

Source

Engineers Components

Sink

Then, we’ve got to add to the cut all of the edges from that node to all of the Components in the graph. The change to the value of the cut is: old value - [jobs for that engineer] + [# of Components NOT in the cut]

Page 8: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Try to put a ComponentSink edge into the cut.

Source

Engineers Components

Sink

Then, we can take out of the cut all of the edges from Engineers not in the cut to that Component. The change in the value of the cut is: old value + [Tasks for that Component] - [# of Engineers NOT in the cut]

Page 9: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

So, here’s our strategy: Sort both the Engineers and Components by

numbers of tasks Remove engineers from the cut from largest to

smallest▪ For each removed engineer, add Components from

smallest to largest▪ Only add components if there’s an improvement:

▪ [Tasks for that Component] < [# of Engineers NOT in the cut] If min cut = sum of all component needs, then

we’ve got a “Yes”. If min cut < that sum, the answer is “No”

Page 10: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Note that once [# of Engineers NOT in the cut] is bigger than any [Tasks for that Component] , then all components are in the cut. That’s a complete cut, and there’s no need to go any further.

But, [Tasks for that Component] is capped at 100,000, so there’s never any need to go any further than 100,000 engineers.

We remove components by comparing [Tasks for that Component] to [# of Engineers NOT in the cut]. But, [Tasks for that Component] is the same for every component in a class. So, we don’t have to go through the components one-by-one, we can remove them in bulk.

Note that Engineers are independent of Components – that is, the effect of manipulating an Engineer is dependent only on the number of Components in/out of the cut, NOT on which ones.

Page 11: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

long eout = 0;long cout = totalcomps;long mincut = Math.min(totalgots,totalneeds);long cut = totalgots;int c = 0; for( int j=m-1; j>=0 && c<n; j-- ){ for( int k=0; k<jobtitles[j].count && c<n; k++ ) { ++eout; cut -= jobtitles[j].amount; cut += cout; while( c<n && comptypes[c].amount<=eout ) { cut += comptypes[c].count * comptypes[c].amount; cut -= comptypes[c].count * eout; cout -= comptypes[c].count; ++c; } if( cut<mincut ) mincut = cut; }}ps.println( (mincut==totalneeds) ? 1 : 0 );

Page 12: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

So, we want to find a and m such that a/m - b/n = (a-b)/(m-n) Do some algebra on the above equation, and you can come up with

this: (an-bm)/nm = (a-b)/(m-n) (m-n)(an-bm) = nm(a-b) anm - an2 - bm2 + bnm = anm - bnm an2 = 2bmn - bm2

a = (2bmn - bm2)/n2

Now, let m=kn for some k a = [2b(kn)n - b(kn)2]/n2

a = [2bkn2 - bk2n2]/n2

a = 2bk - bk2

Page 13: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

The problem is that k doesn't have to be an integer. But, we can limit it. k has to be a rational number - that is, a fraction. Since m=kn and m is an integer, then k's denominator must be a factor of n.

Now, look at a = 2bk - bk2. That's a quadratic in k, with roots at 0 and 2 When k=0, obviously a=0. When k=2, a = 4b-4b = 0. when k=1, a = 2b-b = b. So, since a must be non-negative, 0<=k<=2. That means that k's numerator must be between 0 and 2*denominator.

So, now we have a strategy for looping through k’s potential denominator, and for looping through k’s potential numerator based on its denominator. Loop through them, build a and m and see if they work If they do, put them in a set to sort later There are other things you can do to make it more efficient

Page 14: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

For every essay, keep track of needs and feeds: needs[i] is the number of essays which must come before this one feeds[i] is a list of essays that need this one to come before them On input d and u, ++needs[u], add u to feeds[d].

Keep a list ‘zeros’ of all essays with 0 needs These can be scheduled right away

answer = 1For 1 to the number of essays

If zeros.size==0, then we have a cycle. answer = 0, exit loop. If zeros.size>1, then we’ve got multiple solutions. answer=2,

(but we can’t exit the loop because we might find a cycle later)Take an essay d off of the zeros list.For every essay u in feeds[d], --needs[u]. If needs[u]==0, add u to zeros

Page 15: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Build the Room polygons For each point, keep track of the edges. Sort

them by angle. Trace around a room edge-by-edge. At every

point, take the next edge in the sorted list from the one you came in on▪ If you reach the end of the list, go back to the beginning

Go in both directions Compute area of each room

Area = ½ * | Sum((x2-x1)*(y2+y1)) |

Page 16: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Build a Max Flow graph for Ford/Fulkerson Create 2 nodes for each room: ‘Enter’ and ‘Exit’ Create edges:

For each room, create edge EnterExit with weight equal to the area of the room

For each room with an Entrance, create an edge SourceEnter with weight MAX

For each room with an Exit, create an edge ExitSink with weight MAX

For any two rooms with a door between them create two edges: Exit1Enter2 and Exit2Enter1, each with weight MAX.

Note: For every edge AB you create, you’ll also create a back edge BA with weight 0.

Page 17: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Backtracking, with a lot of pruning. The number of consecutive composites is surprisingly small

For the limits of this problem (1010), the largest “prime gap” is 282 Any prime larger than 282 can only appear once in the sequence

That limits the number of primes for which you have to keep track of whether they’re used or not

For every number in the sequence, build up a list of candidate primes Also build a separate count of primes

Recurse allocating primes to numbers in the sequence Decrement the prime count of every other number with that prime as a candidate Allocate to numbers with 1 remaining possibility first If any number has 0 remaining possibilities, fail right there.

Page 18: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Figure out how many cells have 1 neighbor, 2, 3, 4, 5 “Neighbor” means a cell which can flip it if pressed, including the cell itself

Compute the probability of any cell being a Head after k random presses, if it starts out a head: Let prob[i] be that probability for a cell with i neighbors. Start with prob[i] = 1 For j=1 to k: prob[i] = prob[i]*((ncoins-i)/ncoins) + (1.0-prob[i])*(i/ncoins)

Next, figure out which configurations yield an expected number of heads between a and b

for( int i1=0; i1<=counts[1]; i1++ ) for( int i2=0; i2<=counts[2]; i2++ ) for( int i3=0; i3<=counts[3]; i3++ ) for( int i4=0; i4<=counts[4]; i4++ ) for( int i5=0; i5<=counts[5]; i5++ ){ double expected = i1*prob[1] + (counts[1]-i1)*(1.0-prob[1]); expected += i2*prob[2] + (counts[2]-i2)*(1.0-prob[2]); expected += i3*prob[3] + (counts[3]-i3)*(1.0-prob[3]); expected += i4*prob[4] + (counts[4]-i4)*(1.0-prob[4]); expected += i5*prob[5] + (counts[5]-i5)*(1.0-prob[5]); if( a<=expected && expected<=b ) configs.add( { i1, i2, i3, i4, i5 } );}

Page 19: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Now, what should the board look like? Set base = 0 Start at the top left corner, and iterate

through every spot Start by assuming it is a head Figure out how many satisfactory configurations

follow that prefix If configs >=i, then keep going. If configs <i, then there aren’t enough good

configurations when this cell is a Head. So, it has to be a Tail. Set base = base + configs

Page 20: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

How do we know how many satisfactory board positions follow? Well, we know how many heads of each type we’ve

already seen in the prefix For each still viable configuration, we know how many

heads we need. Then, it’s just:

▪ Sum for each still viable configuration of▪ The product for each type of cell of

(counts[t]-prefix.length) C (config[t]-used[t]) counts[t]- prefix.length is the number of cells of this type that are yet to be

filled config[i]-used[t] is the number of heads we have left C is statistical “Choose” – nCm is the number of ways of choosing m

things out of a group of n, where order is not important. nCm = n!/(m!(n-m)!) (though there are much more efficient ways of

computing it)

Page 21: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Needed= 2*width*height + 2*length*height + length*width Subtract off every w*h for all windows and doors Cans = Needed / area If Needed % area != 0 then add one to Cans

Biggest problem teams had: 0 windows/doors

Page 22: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Seems simple – but it can be tricky! Let’s just look at the middle 2 names:

A, B A AA, B AA AAA, B AB AZZQ, B AZZQ AZZQX, B AZZR FRANK, FRAO FRANL

The best solution is to build substrings (S) of the first string (a) in order of length 1, 2, 3… etc, where the last character of the substring is incremented by 1 Exceptions: If the last character is Z, or if the substring is the original string Stop when you find a string S where a<=S<b For example, if a=EZEKIEL, build strings:

▪ F▪ EZ▪ EZF▪ EZEL▪ EZEKJ▪ EZEKIF▪ EZEKIEL

Page 23: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Just array manipulation.

If you’re really clever, you can reuse code for rows/columns, rather than risking cut-n-paste errors.

Be careful of spaces at the end!

Page 24: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Minimum Spanning Tree for a directed graph

Or, regular MST, with an added restriction. Start with Kruskal, which goes like this:

Start with each node in its own set.▪ If you've got n nodes, then you've got n sets.

Then, sort all of edges by weight (in this case, length or distance). Go through the edges, smallest to largest. If an edge connects two nodes that are in difference sets, then union those two sets,

and add that edge to the Minimum Spanning Tree.

We’ve got to deviate from Kruskal, because of our political restriction.

Page 25: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Suppose the edge looks like this (a’s y > b’s y):

Think about all of the nodes that are in a's set. They're all already connected with edges - that's why they're in the same set.

If any one of them has a smaller y than a, then we risk sending the warning up to a, and then back down again to that lower city. We can't do that.

So, if a has the higher y of the edge, then a's y must be the minimum y of all of the nodes in a's set.

Ditto for b - if it has the larger y, then that y value must be the minimum y of all of the cities in b's set.

If a.y == b.y, then all we require is that ONE of them be the minimum of their set.

a

b

Page 26: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Maintaining the sets can be done in a clever way: as a tree. Create an array parent[i], where parent[i] is the parent of

node I, or -1 if I is the root of its subtree. Use the index of the root as a unique identifier for the set. To merge nodes i and j, just set parent[i]=j

▪ There’s also some trickery you can do here to make things more efficient. You can go up the tree, setting parents as you go, to “squash” the tree, reducing its depth.

▪ This technique will also allow you to same the minimum y value in the set. Just create a miny[i] array. At the start, miny[i] = the y of point I (since every point is its own set).

▪ When you merge I with j, find the root of I’s subtree & j’s subtree, aand set the new root’s miny to be the minimum of the minys of the two roots.

Page 27: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

We’ll compute the count of unhappy numbers from 0 to n. If we need from a to b, then we’ll print unhappy(b) – unhappy(a-1)

A number is unhappy iff the sum of squares of its digits is unhappy.

For all of the numbers in our range, the max sum of squared digits is less than 2000 I believe it’s 1522, for 8999999999999999999

So, we can compute unhappiness for the first 2000 numbers by brute force, put the results into a boolean array, and for every other number, just sum digit squares and index into that boolean array.

But, we can’t do that 1018 times. We need a shortcut.

Page 28: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Strategy: For n, build an array counts[], where counts[i] is a count of the numbers from 0 to n with a squared-digit sum of i.

Then, total all of those counts[i] where unhappy[i] is true

That will give a count of the unhappy numbers from 0 to n

Page 29: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

Now to compute that array. This is a complicated procedure, so we will frame it with a

specific example: x=6724. First, Figure out the highest digit, and its power of 10.

For our example (6724), digit=6, power=1000. Break down the problem by that first digit.

In our example (6724), that means calculating the digit sums for ▪ 0-999▪ then 1000-1999▪ then 2000-2999▪ then 3000-3999▪ then 4000-4999▪ then 5000-5999▪ and finally, 6000-6724.

Page 30: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

First, get the digit sums for all 9s In our example, that’s 999. subsums[] = sumcounts( power-1 ); You can memoize these, since we’ll be using them over and over

Now, go through the first digits In our example, that’s 0-5 for( int d=0; d<digit; d++ ) for( int i=0; i<sums.length-d*d; i++ ) sums[i+d*d] += subsums[i];

Now, handle the biggest digit In our example, that’s 6. x % power = 6724 % 1000 = 724 subsums[] = sumcounts( x % power ); for( int i=0; i<sums.length-digit*digit; i++ ) sums[i+digit*digit] += subsums[i];

Page 31: David Van Brackle Chief Judge, Southeast USA Region, ICPC.

You can’t go through all possible wall positions, there are just too many.

However, you CAN go through all possible wall positions in one dimension, and then use a simple sweep to see where the walls need to be in the other dimension!


Recommended