Friday, May 3, 2013

Google Code Jam - Round1 A 2013 - Manage your Energy

Problem Link:

Manage your Energy

Problem:

Problem Manage your Energy

You've got a very busy calendar today, full of important stuff to do. You worked hard to prepare and make sure all the activities don't overlap. Now it's morning, and you're worried that despite all of your enthusiasm, you won't have the energy to do all of this with full engagement.
You will have to manage your energy carefully. You start the day full of energy - E joulesof energy, to be precise. You know you can't go below zero joules, or you will drop from exhaustion. You can spend any non-negative, integer number of joules on each activity (you can spend zero, if you feel lazy), and after each activity you will regain R joules of energy. No matter how lazy you are, however, you cannot have more than E joules of energy at any time; any extra energy you would regain past that point is wasted.
Now, some things (like solving Code Jam problems) are more important than others. For the ith activity, you have a value vi that expresses how important this activity is to you. The gain you get from each activity is the value of the activity, multiplied by the amount of energy you spent on the activity (in joules). You want to manage your energy so that your total gain will be as large as possible.
Note that you cannot reorder the activities in your calendar. You just have to manage your energy as well as you can with the calendar you have.

Input

The first line of the input gives the number of test cases, TT test cases follow. Each test case is described by two lines. The first contains three integers: E, the maximum (and initial) amount of energy, R, the amount you regain after each activity, and N, the number of activities planned for the day. The second line contains N integers vi, describing the values of the activities you have planned for today.

Output

For each test case, output one line containing "Case #xy", where x is the case number (starting from 1) and y is the maximum gain you can achieve by managing your energy that day.

Limits

1 ≤ T ≤ 100.

Small dataset

1 ≤ E ≤ 5.
1 ≤ R ≤ 5.
1 ≤ N ≤ 10.
1 ≤ vi ≤ 10.

Large dataset

1 ≤ E ≤ 107.
1 ≤ R ≤ 107.
1 ≤ N ≤ 104.
1 ≤ vi ≤ 107.

Sample


Input

Output
3
5 2 2
2 1
5 2 2
1 2
3 3 4
4 1 3 5
Case #1: 12
Case #2: 12
Case #3: 39
In the first case, we can spend all 5 joules of our energy on the first activity (for a gain of 10), regain 2 and spend them on the second activity. In the second case, we spend 2 joules on the first activity, regain them, and spend 5 on the second. In the third case, our regain rate is equal to the maximum energy, meaning we always recover all energy after each activity - so we can spend full 3 joules on each activity.

Solution:

We need to decide the energy we should spend at every task, to decide we will first get the number of tasks after which we can get back the full energy, i.e.n = upper(E/R). Now we see if a task with higher value exists in the next n tasks, if not then we spend all energy in the current task else if we get a task with higher value at position "next", then we should try to maximize the energy for this task (represents as x), since we hope at next, the energy could be E, So, the energy we can spend at the current task
x = current energy + energy gaining while moving  – E. This is like current part + energy we could get in the future - the energy we hope to reach at position "next". Then, there are three possible x,
1st, x <= 0, that means at position "next", we could not have E to spend, so we will spend nothing at current position;
2nd, x > current energy, this is a good news, but the reality tells us we could spend energy more than we actually have at current.
3rd, 0 < x <= current energy, we could spend x energy here now.
This solution is partially from PuzzlersWorld.com. I just elaborate more about it a little bit.

Source Code:

/**
 * 
 */
package com.googlecodejam.yr2013.round1A;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.math.BigInteger;

/**
 * @author antonio081014
 * @time Apr 28, 2013, 2:28:09 PM
 */
public class B {
 BigInteger two = new BigInteger("2");

 public static void main(String[] args) throws Exception {
  B main = new B();
  main.run();
  System.exit(0);
 }

 private void run() throws Exception {
  BufferedReader in = new BufferedReader(new FileReader("input.in"));
  PrintWriter out = new PrintWriter(new FileWriter("output.txt"));
  int T = Integer.parseInt(in.readLine());
  for (int t = 1; t <= T; t++) {
   out.write("Case #" + t + ": ");
   String[] lines = in.readLine().split("\\s");
   long E = Long.parseLong(lines[0]);
   long R = Long.parseLong(lines[1]);
   int N = Integer.parseInt(lines[2]);
   lines = in.readLine().split("\\s");
   long[] array = new long[N];
   for (int i = 0; i < N; i++) {
    array[i] = Long.parseLong(lines[i]);
   }
   String ret = solve(E, R, array);
   out.write(ret + "\n");
  }
  in.close();
  out.close();
 }

 /**
  * Solving each case;
  * */
 private String solve(long E, long R, long[] array) {
  int N = array.length;
  long current = E;
  // This is tricky.
  if (R > E)
   R = E;
  BigInteger total = new BigInteger("0");
  long n = (E + R - 1) / R;
  for (int i = 0; i < N; i++) {
   int next = nextMax(array, i, n);
   // System.out.println(next);
   // When current position holds the max value;
   if (next == -1) {
    total = total.add(new BigInteger(Long.toString(array[i]))
      .multiply(new BigInteger(Long.toString(current))));
    current = R;
   } else {
    // the next position holds the max value, so current position
    // might need to save some energy for the next position.

    // Energy could be consumed at ith;
    long x = current + (next - i) * R - E;
    if (x < 0)
     x = 0;
    if (x > current)
     x = current;
    total = total.add(new BigInteger(Long.toString(array[i]))
      .multiply(new BigInteger(Long.toString(x))));
    current = Math.min(current - x + R, E);
   }
   // System.out.println("Total: " + total.toString());
  }
  return total.toString();
 }

 /**
  * Finding the first position which holds an equal or greater value than the
  * current position, ranges from current+1 to current +n;
  * 
  * @return -1, if current position holds the maximum value. <br/>
  *         i, if ith value is the first value equal or greater than the
  *         current value.
  * */
 private int nextMax(long[] array, int current, long n) {
  for (int i = current + 1; i < array.length && i < current + 1 + n; i++) {
   if (array[i] >= array[current])
    return i;
  }
  return -1;
 }

}

No comments :