Problem B. Fair Warning - Qualification Round 2010 - Google Code Jam


Dashboard - Qualification Round 2010 - Google Code Jam

Problem

On our planet, Jamcode IX, three Great Events occurred. They happened 26000, 11000 and 6000 slarboseconds ago. In 4000 slarboseconds, the amount of time since all of those events will be multiples of 5000 slarboseconds, the largest possible amount... and the apocalypse will come.
Luckily for you, you live on Jamcode X! The apocalypse came on Jamcode IX less than a year ago. But Jamcode X has a worrying prophecy: "After the moment of reckoning, on the first optimum anniversary of the N Great Events, the apocalypse will come. 64 bits will not save you. You have been warned."
The people of Jamcode X are very concerned by this prophecy. All of the Great Events have already happened, and their times have been measured to the nearest slarbosecond; but nobody knows when their optimum anniversary will occur. After studying the diary of a scientist from Jamcode IX, scientists working on the problem have come up with a theory:
The moment of reckoning is now, the moment you solve this problem. At some time y ≥ 0 slarboseconds from now, the number of slarboseconds since each of the Great Events will be divisible by some maximum number T. If you can find the smallest value of y that gives this largest possible T, that will give you the optimum anniversary when the apocalypse will come.
On Jamcode IX, for example, there were 3 Great Events and they happened 26000, 11000 and 6000 slarboseconds before the moment of reckoning. 4000 slarboseconds later, the amount of time since each event was a multiple of T=5000 slarboseconds, and the apocalypse came.
Your job is to compute the amount of time until the apocalypse comes. But remember the prophecy: even though the people of Jamcode X have been solving problems for two years, and 64-bit integers have always been enough, they might not always be enough now or in the future.

Input

The first line of the input gives the number of test cases, C. C lines follow. Each starts with a single integer N, which is followed by a space and then N space-separated integers ti, the number of slarboseconds since Great Event i occurred.

Output

For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the minimum number of slarboseconds until ti + y is a multiple of the largest possible integer factor T for all i.
Official Analysis: https://code.google.com/codejam/contest/433101/dashboard#s=a&a=1
This problem talks about divisors and multiples so it hints at using the greatest common divisor concept in some way. To solve the problem we need to find T and afterwards we can easily find y.
Let's simplify the problem and just look at two numbers a and b. In this case we need to find the largest T so that some positive y exists where a + y and b + y are multiples of T. So (a + y) modulo T = (b + y) modulo T which means that (a - b) modulo T = 0. Thus Tmust be a divisor of |a - b|.

Coming back to the problem with N numbers, we have proved that T must divide every |ti - tj|. This means that the solution is the greatest common divisor of all |ti - tj| numbers. A simple observation can improve our algorithm from O(N2) to O(N) iterations of the Euclidean algorithm. Let's say a ≤ b ≤ c, then gcd(b - a, c - a) = gcd(b - a, c - a, c - b). To prove this we look at the first iteration of the Euclidean algorithm. Since a ≤ b ≤ c it means that b - a ≤ c - a so in the first step we subtract b - a from c - agcd(b - a, c - a) = gcd(c - b, b - a), this proves our observation. Now we can just compute the greatest common divisor of all |ti - t1| to find T.

http://articles.leetcode.com/2010/05/problem-b-fair-warning-solution.html
This problem is cryptic in description, but it can be summarize as a Math problem below:
Given a list of positive integers: t1, t2, …, tn, and ti ? tj for some i, j. Find the smallest integer y >= 0 such that each ti + y is divisible by an integer T. T must be the largest of all possible divisors.
Before we go for the general solution, let’s consider the easier case where n=2, and assume t1 is greater than t2.
Therefore,
t1 + y = k1 * T —– (1)
t2 + y = k2 * T —– (2)
ti, y, ki, and T are all integers.
Eq. (1) – (2) gives
t1 – t2 = (k1 – k2) * T
Therefore, we can conclude that t1 – t2 is also divisible by T. Since T must be the largest among all possible divisors, k1 – k2 must equal 1. Why? Consider when k1 – k2 = 2, then the value of T would be halved. We have just found the value of T, which is equal to t1 – t2.
After we have found the value of T, we can obtain value of y. From the previous information that k1 – k2 = 1, we can deduce from Eq. (1) and (2) that k2 = 1 and k1 = 2. Why not k2 = 2 and k1 = 3? Recall that y is the smallest value that fulfill the requirement.
Substituting in Eq. (2), we get
y = k2 * T – t2
= 1 * (t1 – t2) – t2
= t1 – 2 * t2
We have solved the easy case. Now generalize for all cases. You can probably see that for n >= 3, the value of T is equal to the Greatest Common Divisor (GCD) of all possible ti – tj, i ? j, ti > tj. Note that finding all such possible pairs of i and j takes O(n^2) time.
Once we found the value of T, we can then solve for y.
For large input, you have to use a Big Integer library and there is one possible optimization. When a = b = c, then gcd(b – a, c – a) = gcd(b – a, c – a, c – b). Taking advantage of this property, we are able to reduce the GCD step from O(n^2) to O(n).
long long gcd(long long a, long long b) {
  if (b == 0)
    return a;
  return gcd(b, a % b);
}
 
long long gcd(long long arr[], int n) {
  long long temp = arr[0];
  for (int i = 1; i < n; i++) {
    temp = gcd(temp, arr[i]);
  }
  return temp;
}
 
int n, m;
long long arr[1400], arr2[100000];
  cin >> n;
for (int i = 0; i < n; i++) {
  cin >> m;
  for (int j = 0; j < m; j++)
    cin >> arr[j];
 
  sort(arr, arr+m);
  int sz = 0;
  for (int j = m-1; j >=0; j--) {
    for (int k = j-1; k >= 0; k--) {
      arr2[sz++] = arr[j]-arr[k];
    }
  }
  long long T = gcd(arr2, sz);
  long long ans = (ceil((double)arr[0] / T))*T - arr[0];
  cout << "Case #" << i+1 << ": " << ans << endl;
}
You can first calculate T (the optimal anniversary) by looking at the gcd (greatest common divisor) of the differences between the time elapsed since the events. This works because in order for T to divide the time elapsed since the events, it must also divide the time elapsed between the events. After that, you just need to find the first y that makes any of the numbers divisible by T. I just wrote out the congruences on my whiteboard (which I probably shouldn’t have needed to do) then typed in my answer.
def gcd(x,y):
    while x:
        x, y = y % x, x
    return y

testcases = open("warning.in").readlines()
t = 1
for tc in testcases[1:]:
  tc = map(lambda x: int(x), tc.split(" ")[1:])
  if len(tc) == 0:
    break
  tc.sort()
  #print tc

  diff = []
  for i in range(len(tc)-1):
    diff += [tc[i+1] - tc[i]]

  T = diff[0]
  for d in diff[1:]:
    T = gcd(T,d)

  #print T
  print "Case #%d: %d" % (t, (-tc[0] % T))

  t += 1

static String process(String line){
String[] parts = line.split("[ ]");
BigInteger[] values = new BigInteger[parts.length-1];
for(int i=1;i<parts.length;i++){
values[i-1] = new BigInteger(parts[i]);
}
Arrays.sort(values);
BigInteger dev = values[1].subtract(values[0]);
for(int i=0;i<values.length-2;i++){
BigInteger b = values[i+2].subtract(values[i+1]);
dev = dev.gcd(b);
}
BigInteger buf = values[0].mod(dev);
if(buf.compareTo(BigInteger.valueOf(0))==0){
return "0";
}
buf = dev.subtract(buf);
return buf.toString();
}

public static BigInteger GCD(BigInteger A, BigInteger B) {
if(B.equals(BigInteger.ZERO))return A;
return GCD(B,A.mod(B));
}
Read full article from Dashboard - Qualification Round 2010 - Google Code Jam

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts