package com.anuragkapur.fb.hackercup2013.qr;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
/**
* @author anurag.kapur
* @status CORRECT
*/
public class FindTheMin {
public int calculateLastElement(int n, int k, int a, int b, int c, int r) {
System.out.println("Will begin calculations :: " + n + " " + k + " " + a + " " + b + " " + c + " " + r);
int indicesOfFirstKIntegers[] = new int[k];
for (int i = 0; i < indicesOfFirstKIntegers.length; i++) {
// Initialize to -1 to say first k integers to start with don't
// figure in the first k numbers the pseudo-random number generates
indicesOfFirstKIntegers[i] = -1;
}
// Go over k elements that the number generator function produces, and
// fill in array positions 0..k-1 where appropriate
if(a < k){
indicesOfFirstKIntegers[a] = 0;
}
int previous = a;
for(int i = 1; i < k; i++) {
long temp = (long) b * previous;
temp = (long) temp + c;
temp = (long) temp % r;
String tempStr = temp + "";
int current = Integer.parseInt(tempStr);
// Update indicesOfFirstKIntegers
if (current < k) {
indicesOfFirstKIntegers[current] = i;
}else {
// Just ignore it, this value can never be the answer. Answer
// lies in the set [0,k-1] both numbers inclusive
}
//current becomes previous for next iteration
previous = current;
}
int answer = 0;
int pointer = k;
byte secondSetOfK[] = new byte[k];
boolean answerFound = false;
for (int i = 0; i < k; i++) {
//System.out.println("Indices of :: " + i);
int index = indicesOfFirstKIntegers[i];
if (index < 0) {
for (int j = 0; j < secondSetOfK.length; j++) {
if(secondSetOfK[j] == 0) {
// This is a free space, take it.
secondSetOfK[j] = 1;
pointer = j + k;
break;
}
}
indicesOfFirstKIntegers[i] = pointer;
//System.out.println(" >> " + pointer);
// See if this could be solution
int nextIndex = pointer;
while (nextIndex <= n-1) {
//System.out.println(" >> " + nextIndex);
if (nextIndex == n-1) {
answer = i;
answerFound = true;
break;
}else {
nextIndex = nextIndex + k + 1;
}
}
if (answerFound) {
break;
}
}else {
// Use index at index + k + 1
int temp = index + k + 1;
if(temp - k > k -1) {
// Array out of bound, so dont do any more calculations.
continue;
}
if (secondSetOfK[temp - k] == 0) {
// This space is free to be taken.
indicesOfFirstKIntegers[i] = temp;
secondSetOfK[temp - k] = 1;
//System.out.println(" << " + temp + " index = " + index);
}else {
// Find the next free space, since this is already taken
for (int j = temp - k + 1; j < secondSetOfK.length; j++) {
if (secondSetOfK[j] == 0) {
// This is a free space, take it
temp = j + k;
secondSetOfK[j] = 1;
indicesOfFirstKIntegers[i] = temp;
//System.out.println(" << " + temp + " index = " + index);
break;
}
}
}
// See if this could be solution
int nextIndex = temp;
while (nextIndex <= n-1) {
//System.out.println(" << " + nextIndex);
if (nextIndex == n-1) {
answer = i;
answerFound = true;
break;
}else {
nextIndex = nextIndex + k + 1;
}
}
if (answerFound) {
break;
}
}
}
return answer;
}
public void writeOutputToFile(String output, String filepath)
throws IOException {
FileWriter fstream = new FileWriter(filepath);
BufferedWriter out = new BufferedWriter(fstream);
out.write(output);
out.flush();
out.close();
}
/**
* @param args
*/
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Not enough command line arguments specified. Need 2 (Input and output file paths)");
return;
}
String inputFilePath = args[0];
try {
// String buffer for storing the output
StringBuffer output = new StringBuffer();
// Instantiate object to use non static methods
FindTheMin finder = new FindTheMin();
// read and parse input file
FileInputStream fstream = new FileInputStream(inputFilePath);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
int lineNumber = 0;
int noOfTestCases = -1;
int activeTestCaseNumber = 0;
int n = 0, k = 0, a, b, c, r;
boolean startOfTestCase = true;
while ((strLine = br.readLine()) != null) {
if (lineNumber == 0) {
noOfTestCases = Integer.parseInt(strLine);
} else {
if (startOfTestCase) {
noOfTestCases ++;
activeTestCaseNumber ++;
StringTokenizer tokenizer = new StringTokenizer(strLine, " ");
n = Integer.parseInt(tokenizer.nextToken());
k = Integer.parseInt(tokenizer.nextToken());
startOfTestCase = false;
}else {
startOfTestCase = true;
StringTokenizer tokenizer = new StringTokenizer(strLine, " ");
a = Integer.parseInt(tokenizer.nextToken());
b = Integer.parseInt(tokenizer.nextToken());
c = Integer.parseInt(tokenizer.nextToken());
r = Integer.parseInt(tokenizer.nextToken());
// Now that a test case has been parsed, compute output for
// this test case
// Invoke algorithm here
String solutionToTestCase = finder.calculateLastElement(n, k, a, b, c, r) + "";
// Prepare output string
System.out.println("Case #" + activeTestCaseNumber + ": " + solutionToTestCase);
output.append("Case #" + activeTestCaseNumber + ": " + solutionToTestCase);
output.append("\n");
}
}
lineNumber++;
}
in.close();
// Pass output string to method to write to file
finder.writeOutputToFile(output.toString(), args[1]);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// File read cleanup
}
}
}