// NOTE: I wrote a Python program to generate all possible combinations // of 5 indices in range 0..15 that could correspond to rolling 5, 6, ..., 15 // dice according to Yahtzee rules; that program is tacked on at the end // of this as a long comment. I then pasted the output from that Python program // into this Java program. import java.util.*; public class Seq_bob { public static Scanner in; public static int n; public static int rolls[]; public static int grid[][]; public static int[][][] index; public static void main(String[] args) { in = new Scanner(System.in); n = in.nextInt(); rolls = new int[n+1]; for (int i = 1; i <= n; i++) { // skip 0--leave it for initial condition rolls[i] = in.nextInt(); } // I used a Python program to create this lookup table of index // offsets for 5, 6, ..., 15 dice. I cleaned it up a little for // readability, but you probably don't want to read it. index = new int[][][]{ {}, {}, {}, {}, {}, // rolls 0--4 are empty // rolls = 5 { { 0, 1, 2, 3, 4} }, // rolls = 6 { { 1, 2, 3, 4, 5}, { 0, 2, 3, 4, 5}, { 0, 1, 3, 4, 5}, { 0, 1, 2, 4, 5}, { 0, 1, 2, 3, 5} }, // rolls = 7 { { 2, 3, 4, 5, 6}, { 1, 3, 4, 5, 6}, { 1, 2, 4, 5, 6}, { 1, 2, 3, 5, 6}, { 1, 2, 3, 4, 6}, { 0, 3, 4, 5, 6}, { 0, 2, 4, 5, 6}, { 0, 2, 3, 5, 6}, { 0, 2, 3, 4, 6}, { 0, 1, 4, 5, 6}, { 0, 1, 3, 5, 6}, { 0, 1, 3, 4, 6}, { 0, 1, 2, 5, 6}, { 0, 1, 2, 4, 6}, { 0, 1, 2, 3, 6} }, // rolls = 8 { { 3, 4, 5, 6, 7}, { 2, 4, 5, 6, 7}, { 2, 3, 5, 6, 7}, { 2, 3, 4, 6, 7}, { 1, 4, 5, 6, 7}, { 1, 3, 5, 6, 7}, { 1, 3, 4, 6, 7}, { 1, 2, 5, 6, 7}, { 1, 2, 4, 6, 7}, { 1, 2, 3, 6, 7}, { 0, 4, 5, 6, 7}, { 0, 3, 5, 6, 7}, { 0, 3, 4, 6, 7}, { 0, 2, 5, 6, 7}, { 0, 2, 4, 6, 7}, { 0, 2, 3, 6, 7}, { 0, 1, 5, 6, 7}, { 0, 1, 4, 6, 7}, { 0, 1, 3, 6, 7}, { 0, 1, 2, 6, 7}, { 2, 3, 4, 5, 7}, { 1, 3, 4, 5, 7}, { 1, 2, 4, 5, 7}, { 1, 2, 3, 5, 7}, { 0, 3, 4, 5, 7}, { 0, 2, 4, 5, 7}, { 0, 2, 3, 5, 7}, { 0, 1, 4, 5, 7}, { 0, 1, 3, 5, 7}, { 0, 1, 2, 5, 7} }, // rolls = 9 { { 4, 5, 6, 7, 8}, { 3, 5, 6, 7, 8}, { 2, 5, 6, 7, 8}, { 3, 4, 6, 7, 8}, { 2, 4, 6, 7, 8}, { 2, 3, 6, 7, 8}, { 1, 5, 6, 7, 8}, { 1, 4, 6, 7, 8}, { 1, 3, 6, 7, 8}, { 1, 2, 6, 7, 8}, { 0, 5, 6, 7, 8}, { 0, 4, 6, 7, 8}, { 0, 3, 6, 7, 8}, { 0, 2, 6, 7, 8}, { 0, 1, 6, 7, 8}, { 3, 4, 5, 7, 8}, { 2, 4, 5, 7, 8}, { 2, 3, 5, 7, 8}, { 2, 3, 4, 7, 8}, { 1, 4, 5, 7, 8}, { 1, 3, 5, 7, 8}, { 1, 3, 4, 7, 8}, { 1, 2, 5, 7, 8}, { 1, 2, 4, 7, 8}, { 1, 2, 3, 7, 8}, { 0, 4, 5, 7, 8}, { 0, 3, 5, 7, 8}, { 0, 3, 4, 7, 8}, { 0, 2, 5, 7, 8}, { 0, 2, 4, 7, 8}, { 0, 2, 3, 7, 8}, { 0, 1, 5, 7, 8}, { 0, 1, 4, 7, 8}, { 0, 1, 3, 7, 8}, { 0, 1, 2, 7, 8}, { 3, 4, 5, 6, 8}, { 2, 4, 5, 6, 8}, { 1, 4, 5, 6, 8}, { 2, 3, 5, 6, 8}, { 1, 3, 5, 6, 8}, { 1, 2, 5, 6, 8}, { 0, 4, 5, 6, 8}, { 0, 3, 5, 6, 8}, { 0, 2, 5, 6, 8}, { 0, 1, 5, 6, 8} }, // rolls = 10 { { 5, 6, 7, 8, 9}, { 2, 6, 7, 8, 9}, { 4, 6, 7, 8, 9}, { 3, 6, 7, 8, 9}, { 1, 6, 7, 8, 9}, { 0, 6, 7, 8, 9}, { 4, 5, 7, 8, 9}, { 3, 5, 7, 8, 9}, { 3, 4, 7, 8, 9}, { 2, 5, 7, 8, 9}, { 2, 4, 7, 8, 9}, { 2, 3, 7, 8, 9}, { 1, 5, 7, 8, 9}, { 1, 4, 7, 8, 9}, { 1, 3, 7, 8, 9}, { 1, 2, 7, 8, 9}, { 0, 5, 7, 8, 9}, { 0, 4, 7, 8, 9}, { 0, 3, 7, 8, 9}, { 0, 2, 7, 8, 9}, { 0, 1, 7, 8, 9}, { 4, 5, 6, 8, 9}, { 3, 5, 6, 8, 9}, { 3, 4, 6, 8, 9}, { 3, 4, 5, 8, 9}, { 2, 5, 6, 8, 9}, { 2, 4, 6, 8, 9}, { 2, 4, 5, 8, 9}, { 1, 5, 6, 8, 9}, { 1, 4, 6, 8, 9}, { 1, 4, 5, 8, 9}, { 2, 3, 6, 8, 9}, { 2, 3, 5, 8, 9}, { 1, 3, 6, 8, 9}, { 1, 3, 5, 8, 9}, { 1, 2, 6, 8, 9}, { 1, 2, 5, 8, 9}, { 0, 5, 6, 8, 9}, { 0, 4, 6, 8, 9}, { 0, 4, 5, 8, 9}, { 0, 3, 6, 8, 9}, { 0, 3, 5, 8, 9}, { 0, 2, 6, 8, 9}, { 0, 2, 5, 8, 9}, { 0, 1, 6, 8, 9}, { 0, 1, 5, 8, 9}, { 4, 5, 6, 7, 9}, { 1, 5, 6, 7, 9}, { 3, 5, 6, 7, 9}, { 2, 5, 6, 7, 9}, { 0, 5, 6, 7, 9} }, // rolls = 11 { { 6, 7, 8, 9, 10}, { 3, 7, 8, 9, 10}, { 5, 7, 8, 9, 10}, { 4, 7, 8, 9, 10}, { 2, 7, 8, 9, 10}, { 1, 7, 8, 9, 10}, { 0, 7, 8, 9, 10}, { 5, 6, 8, 9, 10}, { 4, 6, 8, 9, 10}, { 4, 5, 8, 9, 10}, { 3, 6, 8, 9, 10}, { 3, 5, 8, 9, 10}, { 3, 4, 8, 9, 10}, { 2, 6, 8, 9, 10}, { 2, 5, 8, 9, 10}, { 2, 4, 8, 9, 10}, { 1, 6, 8, 9, 10}, { 1, 5, 8, 9, 10}, { 1, 4, 8, 9, 10}, { 2, 3, 8, 9, 10}, { 1, 3, 8, 9, 10}, { 1, 2, 8, 9, 10}, { 0, 6, 8, 9, 10}, { 0, 5, 8, 9, 10}, { 0, 4, 8, 9, 10}, { 0, 3, 8, 9, 10}, { 0, 2, 8, 9, 10}, { 0, 1, 8, 9, 10}, { 5, 6, 7, 9, 10}, { 4, 6, 7, 9, 10}, { 4, 5, 7, 9, 10}, { 4, 5, 6, 9, 10}, { 1, 6, 7, 9, 10}, { 1, 5, 7, 9, 10}, { 1, 5, 6, 9, 10}, { 3, 6, 7, 9, 10}, { 3, 5, 7, 9, 10}, { 3, 5, 6, 9, 10}, { 2, 6, 7, 9, 10}, { 2, 5, 7, 9, 10}, { 2, 5, 6, 9, 10}, { 0, 6, 7, 9, 10}, { 0, 5, 7, 9, 10}, { 0, 5, 6, 9, 10}, { 5, 6, 7, 8, 10} }, // rolls = 12 { { 7, 8, 9, 10, 11}, { 4, 8, 9, 10, 11}, { 6, 8, 9, 10, 11}, { 5, 8, 9, 10, 11}, { 3, 8, 9, 10, 11}, { 2, 8, 9, 10, 11}, { 1, 8, 9, 10, 11}, { 0, 8, 9, 10, 11}, { 6, 7, 9, 10, 11}, { 5, 7, 9, 10, 11}, { 5, 6, 9, 10, 11}, { 4, 7, 9, 10, 11}, { 4, 6, 9, 10, 11}, { 4, 5, 9, 10, 11}, { 1, 7, 9, 10, 11}, { 1, 6, 9, 10, 11}, { 1, 5, 9, 10, 11}, { 3, 7, 9, 10, 11}, { 3, 6, 9, 10, 11}, { 3, 5, 9, 10, 11}, { 2, 7, 9, 10, 11}, { 2, 6, 9, 10, 11}, { 2, 5, 9, 10, 11}, { 0, 7, 9, 10, 11}, { 0, 6, 9, 10, 11}, { 0, 5, 9, 10, 11}, { 6, 7, 8, 10, 11}, { 5, 7, 8, 10, 11}, { 5, 6, 8, 10, 11}, { 5, 6, 7, 10, 11} }, // rolls = 13 { { 8, 9, 10, 11, 12}, { 5, 9, 10, 11, 12}, { 7, 9, 10, 11, 12}, { 6, 9, 10, 11, 12}, { 4, 9, 10, 11, 12}, { 1, 9, 10, 11, 12}, { 3, 9, 10, 11, 12}, { 2, 9, 10, 11, 12}, { 0, 9, 10, 11, 12}, { 7, 8, 10, 11, 12}, { 6, 8, 10, 11, 12}, { 6, 7, 10, 11, 12}, { 5, 8, 10, 11, 12}, { 5, 7, 10, 11, 12}, { 5, 6, 10, 11, 12} }, // rolls = 14 { { 9, 10, 11, 12, 13}, { 6, 10, 11, 12, 13}, { 8, 10, 11, 12, 13}, { 7, 10, 11, 12, 13}, { 5, 10, 11, 12, 13} }, // rolls = 15 { { 10, 11, 12, 13, 14} }}; grid = new int[14][n+1]; // extra row and col for initial conditions for (int row = 1; row <= 13; row++) { int bound = Math.min(n-65+5*row,row*15); // leave at least 65-5*row dice // Earliest we can compute row entry is after at least 5*row dice rolled for (int col = 5*row; col <= bound; col++) { int max = 0; // Maximize over # of extra rolls ("xrolls") taken to get here. We can // use at most 15 dice, so we could go back up to 14 columns // from the current one. // (e.g., xrolls=0 means we rolled only 5 dice, xrolls=1 means // we re-rolled one of them, ...) int lowb = 5*row-5; // any col from here back must be previous category for (int xrolls = 0; xrolls <= 10; xrolls++) { if (col - xrolls < 5*row) break; // can't use dice lower than this if (col-5-xrolls < lowb) break; // outside bounds if (col-5-xrolls > (row-1)*15) continue; // not enough extra rolls int best = bestof(row,col-4-xrolls,col); int score = best + grid[row-1][col-5-xrolls]; if (score > max) { max = score; } } grid[row][col] = max; } } // Final answer is the best entry in row 13: int ans = 0; for (int i = 65; i <= n; i++) { if (grid[13][i] >= ans) ans = grid[13][i]; } System.out.println(ans); } // Out of all possible valid combinations of the dice from startcol // through endcol, find best score for a given row. public static int bestof(int row, int startcol, int endcol) { int d = endcol-startcol+1; int ind[][] = index[d]; // note: indices have to be offset with actual startcol if (row <= 6) { // the "counting" entries int max = 0; for (int[] x : ind) { max = Math.max(max,count(row,startcol,x)); if (max==5) return row*5; // no need to look further } return row*max; } if (row == 7) { // 3 of a kind int max = 0; for (int[] x : ind) { max = Math.max(max,ofakind(3,startcol,x)); if (max==30) return 30; // largest possible sum of dice } return max; } if (row == 8) { // 4 of a kind int max = 0; for (int[] x : ind) { max = Math.max(max,ofakind(4,startcol,x)); if (max==30) return 30; // largest possible sum of dice } return max; } if (row == 9) { // full house for (int[] x : ind) { if (fullhouse(startcol,x)==25) return 25; } return 0; } if (row == 10) { // small straight for (int[] x : ind) { if (straight(4,startcol,x) == 30) return 30; } return 0; } if (row == 11) { // large straight for (int[] x : ind) { if (straight(5,startcol,x) == 40) return 40; } return 0; } if (row == 12) { // chance int max = 0; for (int[] x : ind) { max = Math.max(max, chance(startcol,x)); if (max == 30) return 30; } return max; } else { // yahtzee for (int[] x : ind) { if (yahtzee(startcol,x)==50) return 50; } return 0; } } // returns number of occurrences of goal (max 5): public static int count(int goal, int s, int[] ind) { int ans = 0; for (int i = 0; i <= 4; i++) if (rolls[s+ind[i]]==goal) ans++; return ans; } // Return sum of dice if there are k of a kind (k = 3 or 4), else return 0 public static int ofakind(int k, int s, int[] ind) { int sum = 0; int count[] = new int[7]; for (int i = 0; i <= 4; i++) { sum += rolls[s+ind[i]]; count[rolls[s+ind[i]]]++; } for (int i = 1; i <= 6; i++) { if (count[i] >= k) return sum; } return 0; } // Return 25 if dice are x,x,y,y,y with x != y, else return 0 public static int fullhouse(int s, int[] ind) { int temp[] = new int[5]; for (int i = 0; i < 5; i++) temp[i] = rolls[s+ind[i]]; Arrays.sort(temp); if (temp[0]==temp[1] && temp[3]==temp[4] && (temp[2]==temp[1] || temp[2]==temp[3]) && temp[0] != temp[4]) return 25; return 0; } // return 30 or 40 if there is a small or large straight, 0 otherwise public static int straight(int k, int s, int[] ind) { int[] temp = new int[5]; for (int i = 0; i < 5; i++) temp[i] = rolls[s+ind[i]]; int count[] = new int[7]; for (int i = 0; i < 5; i++) { count[temp[i]]++; } // just enumerate the possible cases: if (k==4) { if (count[1]*count[2]*count[3]*count[4] > 0) return 30; if (count[2]*count[3]*count[4]*count[5] > 0) return 30; if (count[3]*count[4]*count[5]*count[6] > 0) return 30; return 0; } // else k must be 5: if (count[1]*count[2]*count[3]*count[4]*count[5] > 0) return 40; if (count[2]*count[3]*count[4]*count[5]*count[6] > 0) return 40; return 0; } // Return sum of all dice public static int chance(int s, int[] ind) { if (ind.length != 5) System.out.println("Error in chance"); int sum = 0; for (int i = 0; i <= 4; i++) sum += rolls[s+ind[i]]; return sum; } // Return 50 if 5 of a kind, else 0 public static int yahtzee(int s, int[] ind) { if (ind.length != 5) System.out.println("Error in yahtzee"); for (int i = 1; i <= 4; i++) { if (rolls[s+ind[i]] != rolls[s+ind[i-1]]) return 0; } return 50; } } /* Here's the Python program that generated the index lists: # returns a list of all combinations of elements of list l taken k at a time: def comb(l,k): n = len(l) if k==0: return [] if k==1: return sorted([[x] for x in l]) if k==n: return [l] ans = [] for i in range(n): newl = l[(i+1):] rslt = [x+[l[i]] for x in comb(newl,k-1)] rslt.sort() ans.extend(rslt) return ans # generates all sets of 5 integers in the range [0..d] that correspond to # valid Yahtzee rolls: for d in range(5,16): finallist = [] # start with first roll of five: [0,1,2,3,4] dice = [0,1,2,3,4] # second roll (if any) consists of between max(1,d-10) and min(5,d-5) dice lim0 = max(1,d-10) lim1 = min(5,d-5) if range(lim0,lim1+1) == []: finallist.append(dice) else: for secondroll in range(lim0,lim1+1): ind = comb([0,1,2,3,4],secondroll) # combinations of indices for s in ind: k = 5 newdice = [i for i in dice] # replace some dice with newly rolled dice for i in s: newdice[i] = k k += 1 newdice.sort() # Third roll, if any, has max(0,d-5-secondroll) dice if d-5-secondroll > 0: ind = comb([0,1,2,3,4],d-5-secondroll) for s in ind: k = 5+secondroll newdice2 = [i for i in newdice] # replace some dice with newly rolled dice for i in s: newdice2[i] = k k += 1 newdice2.sort() if newdice2 not in finallist: finallist.append(newdice2) else: # only if there is no third roll if newdice not in finallist: finallist.append(newdice) # print list in Java array format: print "// rolls =",d print "{", for l in finallist[:-1]: print "{", for s in l[:-1]: print "{},".format(s), print "{}}},".format(l[-1]), print "{", for s in finallist[-1][:-1]: print "{},".format(s), print "{}}}".format(finallist[-1][-1]), print "};" */