In this HackerRank Stone Piles problem solution, There are N piles of stones where the ith pile has Xi stones in it. Alice and Bob play the following game:

  • Alice starts, and they alternate turns.
  • In a turn, a player can choose any one of the piles of stones and divide the stones in it into any number of unequal piles such that no two of the newly created piles have the same number of stones. For example, if there 8 stones in a pile, it can be divided into one of these set of piles: (1,2,5), (1,3,4), (1,7), (2,6) or (3,5). 
  • The player who cannot make a move (because all the remaining piles are indivisible) loses the game.

Given the starting set of piles, who wins the game assuming both players play optimally (that means they will not make a move that causes them to lose the game if some better, winning move exists)?

HackerRank Stone Piles problem solution


Problem solution in Python.

#!/bin/python3

import os
import sys

#
# Complete the stonePiles function below.
#
def mex(l):
    l = sorted(set(l))
    for i,x in enumerate(l):
        if i != x:
            return i
    return len(l)

def sg(n, sg_cache=None):
    #print("sg",n,sg_cache)
    if n <= 2:
        return 0
    if sg_cache and not (sg_cache[n] is None):
        #print("cached",n,sg_cache[n])
        return sg_cache[n]
    def successors(m, beg):
        l = []
        for i in range(beg+1,(1+m)//2):
            sgi = sg(i, sg_cache)
            l.append(sgi ^ sg(m-i, sg_cache))
            for j in successors(m-i, i):
                l.append(sgi ^ j)
        return l
    ret = mex(successors(n, 0))
    sg_cache[n] = ret
    #print("computed",n,ret)
    return ret

def sgl(l):
    sg_cache = [0,0,0]+[None]*(max(l)-2)
    ret = 0
    for n in l:
        ret ^= sg(n, sg_cache)
    return ret, sg_cache

def stonePiles(l):
    return ["BOB","ALICE"][sgl(l)[0] != 0]

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    t = int(input())

    for t_itr in range(t):
        arr_count = int(input())

        arr = list(map(int, input().rstrip().split()))

        result = stonePiles(arr)

        fptr.write(result + '\n')

    fptr.close()


Problem solution in Java.

import java.util.*;
import java.io.*;
public class Solution {
	public static void main(String args[])
	{
		new Solution();
	}
	
	HashMap<Integer, Integer> sgnums;
	ArrayList<ArrayList<Integer>> groups[][];
 	public Solution()
	{
 		groups = new ArrayList[55][55];
 		sgnums = new HashMap();
 		sgnums.put(0, 0);
 		sgnums.put(1, 0);
 		sgnums.put(2, 0);
 		Scanner sc = new Scanner(System.in);
		
		int n = new Integer(sc.nextLine());
		for(int c = 0; c < n; c++)
		{
			sc.nextLine();
			String[] info = sc.nextLine().split(" ");
			ArrayList<Integer> position = new ArrayList();
			for(String s: info)
			{
				int pile = new Integer(s);
				if(pile >= 3)
					position.add(pile);
			}
			if(sg(position) != 0)
				System.out.println("ALICE");
			else
				System.out.println("BOB");
		}
	}
 	
 	public int sg(ArrayList<Integer> arr)
 	{
 		int ret = 0;
 		for(Integer i: arr)
 		{
 			ret ^= sg(i);
 		}
 		return ret;
 	}
 	
 	public int sg(int n)
 	{
 		Integer ret = sgnums.get(n);
 		if(ret != null)
 			return ret;
 		
 		ArrayList<ArrayList<Integer>> groups = groups(1, n);
 		HashSet<Integer> mex = new HashSet();
 		for(ArrayList<Integer> arr: groups)
 		{
 			if(arr.size() > 1)
 				mex.add(sg(arr));
 		}
 		for(int i = 0; ;i++)
 		{
 			if(!mex.contains(i))
 			{
 				sgnums.put(n, i);
 				return i;
 			}
 		}
 	}
 	
 	public ArrayList<ArrayList<Integer>> groups(int startFrom, int target)
 	{
 		if(target == 0)
 		{
 			ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>();
 			ret.add(new ArrayList());
 			return ret;
 		}
 		if(startFrom > target)
 			return new ArrayList<ArrayList<Integer>>();
 		if(target < 0)
 			return new ArrayList<ArrayList<Integer>>();
 			
 		if(groups[startFrom][target] != null)
 			return groups[startFrom][target];
 		ArrayList<ArrayList<Integer>> ret = new ArrayList(); 		
 		ArrayList<ArrayList<Integer>> take = groups(startFrom+1, target-startFrom);
 		for(ArrayList<Integer> arr: take)
 		{
 			ArrayList<Integer> addArr = (ArrayList<Integer>) arr.clone();
 			addArr.add(startFrom);
 			ret.add(addArr);
 		}
 		
		ArrayList<ArrayList<Integer>> notake = groups(startFrom+1, target);
		for(ArrayList<Integer> arr: notake)
 		{
			ArrayList<Integer> addArr = (ArrayList<Integer>) arr.clone();
 			ret.add(addArr);
 		}
 		
 		groups[startFrom][target] = ret;
 		return ret;
 	}
}


Problem solution in C++.

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

const int maxN = 50;
const int maxX = 50;
const int maxSG = 50;

int TN, TC;

int N;

int stone[maxN];

int SG[maxX + 1];

bool mark[maxSG + 1];

void search_split (int dep, int num, int start, int sum)
{
  if (dep >= 2 && num == 0)
  {
#ifdef DEBUG
    if (sum + 1 > maxSG)
      printf("need more SG\n");
#endif
    mark[sum] = true;
    return;
  }

  for (int i = start; i <= num; ++i)
  {
    search_split(dep + 1, num - i, i + 1, sum ^ SG[i]);
  }
}

void calcSG ()
{
  SG[1] = SG[2] = 0;
  for (int i = 3; i <= maxX; ++i)
  {
    memset(mark, false, maxSG + 1);
    search_split(0, i, 1, 0);
    int x = 0;
    while (mark[x])
      ++x;
    SG[i] = x;
  }
#ifdef DEBUG
  for (int i = 1; i <= maxX; ++i)
    printf("%d: %d\n", i, SG[i]);
#endif
}

int main ()
{
  calcSG();
  scanf("%d", &TN);
  for (TC = 1; TC <= TN; ++TC)
  {
    scanf("%d", &N);
    for (int i = 0; i < N; ++i)
      scanf("%d", &stone[i]);

    int sum = 0;
    for (int i = 0; i < N; ++i)
      sum ^= SG[stone[i]];

    if (sum != 0)
      printf("ALICE\n");
    else
      printf("BOB\n");
  }
}


Problem solution in C.

#include<stdio.h>

int main()
{
    int t,i,n=1,g[51]={0},x,tmp;

    for(i=3;i<=8;i++)
    {
        if(i&(i-1))
        {
            g[i]=n;
            n++;
        }
    }

    for(i=9;i<51;i++)
    {
        g[i]=n;
        n++;
    }

    scanf("%d",&t);

    while(t--)
    {
        x=0;
        scanf("%d",&n);

        for(i=0;i<n;i++)
        {
            scanf("%d",&tmp);
            x^=g[tmp];
        }

        if(x) printf("ALICE");
        else printf("BOB");

        printf("\n");
    }

    return 0;
}