两个AC解 - 作弊中头奖(Hit the Jackpot)
原题: http://poj.org/problem?id=3002
Description
Bill has found the perfect way to make money playing the slot machines.
After months of careful research, he has finally figured out the
mechanics behind how the machines operate. Now he is ready to make
profit of his findings.
But first an introduction to the game. A slot machine consists of a
number of wheels, usually three or four, each with a number of symbols
printed on it – cherries, oranges, bells, etc. – and will show one of
its symbols at a given time. To play, you insert a coin, push a button
and the wheels start spinning. After spinning for a while, each wheel
stops – at random it seems – at one of its symbols. If all wheels stop
at the same symbol, or some nice combination of symbols, the player
wins. One combination that is especially desirable is having the jackpot
symbol on all wheels. This combination is simply called ’jackpot’ and
will make you rich for life.
What Bill has discovered is that each wheel will stop at the jackpot
symbol with a certain periodicity, which differs a lot between wheels.
He has also figured out (after some sneeking around at the slot-machine
factory) that all newly manufactured slot-machines are delivered showing
the jackpot combination, and that they all have a counter at the back,
telling how many times the machine has been played. This counter is
always set to zero at delivery.
Now, all Bill needs to do is to calculate the number of times a machine
has to be played between two occurrences of the jackpot combination. We
will call this number the jackpot periodicity. This is of course the
same as the number of times the machine has to be played after leaving
the factory, before it gives its first jackpot. Thus, with a glance at
the counter on the back of a machine, Bill can figure out if it is about
to give a jackpot.
As Bill knows that you are a skillful computer programmer, he turns to
you with the problem of calculating the jackpot periodicity. For each
machine, he will give you the number of wheels, and the periodicity with
which the jackpot symbol shows up on each wheel.
Input
One line with the number of machines n ≤ 20. For each machine, one line
with the number of wheels w ≤ 5, and one line with w numbers, p1 , ...,
pw the periodicity of each wheel pk ≤ 1000.
Output
One line per machine: The jackpot periodicity of the machine, if it is
less than or equal to a billion (109 ), otherwise output the text ’More
than a billion.’.
Sample Input
1
3
10 6 15
分析:问题实际上就是求n个整数的最小公倍数。解题思路参考笔者另外一篇博文“求k-1个数的最小公倍数”。
*****************
解法1: 质因素分解
import java.lang.reflect.Array; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Scanner; /** * * @author ljs * 2011-06-23 * */ public class Main { //factors is returned as factor-count pair,e.g. //n=2*2*2*2*3*5: returns [2,4,3,1,5,1] (factors are in asc. order) private static LinkedList<Integer> findFactors(int n){ LinkedList<Integer> factorList = new LinkedList<Integer>(); int p = n; for(int i=2;i<=p;i++){ int count = 0; while(n % i == 0){ count++; n /= i; } if(count>0){ factorList.add(i); factorList.add(count); } } return factorList; } private static Map<Integer,LinkedList<Integer>> factorAllNumbers(int[] nums){ Map<Integer,LinkedList<Integer>> factoredNumsMap =new HashMap<Integer,LinkedList<Integer>>(); for(int i=0;i<nums.length;i++){ //no need to calculate the factors for duplicate numbers if(factoredNumsMap.get(nums[i]) == null){ LinkedList<Integer> currFactors = Main.findFactors(nums[i]); factoredNumsMap.put(nums[i],currFactors); } } return factoredNumsMap; } private static LinkedList<Integer> findTwoNumbersLCM(LinkedList<Integer> prev,LinkedList<Integer> next){ int j=next.size()-1; //next list's position LinkedList<Integer> curr = new LinkedList<Integer>(prev); if(curr.size()==0){ curr.addAll(next); } for(int i=curr.size()-1;i>=0;i-=2){ int count = curr.get(i); int factor = curr.get(i-1); while(j>=0){ int jcount = next.get(j); int jfactor = next.get(j-1); if(jfactor == factor){ if(jcount>count){ //update the factor's count curr.set(i, jcount); } j-=2; break; }else { if(jfactor > factor){ //insert int insertAt = i + 1; if(insertAt<curr.size()){ curr.add(insertAt,jcount); curr.add(insertAt,jfactor); }else{ curr.addLast(jfactor); curr.addLast(jcount); } j-=2; //don't move i; }else { //add as a first element if(i-1==0){ curr.addFirst(jcount); curr.addFirst(jfactor); j-=2; //i has moved to head position }else{ //don't move j break; } } } } } //insert the least factors at the front while(j>=0){ int jcount = next.get(j); int jfactor = next.get(j-1); curr.addFirst(jcount); curr.addFirst(jfactor); j-=2; } return curr; } private static long findLCM(LinkedList<Integer>[] factorsList){ LinkedList<Integer> currFactors = factorsList[0]; for(int i=1;i<factorsList.length;i++){ LinkedList<Integer> nextFactors = factorsList[i]; currFactors = Main.findTwoNumbersLCM(currFactors, nextFactors); } //caculate the lcm value long lcm = 1; for(int i=0;i<currFactors.size();i+=2){ int factor = currFactors.get(i); int count = currFactors.get(i+1); lcm *= (int)Math.pow(factor, count); } return lcm; } //find the minimum lcm among k-1 numbers (k=nums.length) @SuppressWarnings("unchecked") public static long solve(int[] nums){ Map<Integer,LinkedList<Integer>> factoredNumsMap =Main.factorAllNumbers(nums); int k =nums.length; LinkedList<Integer>[] factorsArr = (LinkedList<Integer>[])Array.newInstance(LinkedList.class,k); for(int j=0;j<k;j++){ factorsArr[j] = factoredNumsMap.get(nums[j]); } long lcm = Main.findLCM(factorsArr); return lcm; } public static void main(String[] args) { Scanner cin = new Scanner(System.in); String line = cin.nextLine(); line = line.trim(); int machinesCount = Integer.parseInt(line); int[][] testCases = new int[machinesCount][]; for (int i = 0; i < machinesCount; i++) { line = cin.nextLine(); line = line.trim(); int w = Integer.parseInt(line); line = cin.nextLine(); line = line.trim(); int[] p = new int[w]; String[] tokens = line.split(" "); for (int j = 0; j < tokens.length; j++) { String token = tokens[j].trim(); if (token.length() > 0 && j < w) { p[j] = Integer.parseInt(token); } } testCases[i] = p; } for (int i = 0; i < machinesCount; i++) { int[] p = testCases[i]; long result = Main.solve(p); if(result<=1000000000){ System.out.println(result); }else{ System.out.println("More than a billion."); } } } }
*****************
解法2: 通过gcd求lcm
import java.lang.reflect.Array; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Scanner; /** * * @author ljs * 2011-06-23 * */ public class Main { public static long gcd(long m,long n){ m = (m<0)?-m:m; n = (n<0)?-n:n; while(n!=0){ long remainder = m%n; m = n; n = remainder; } return m; } public static long solve(int[] nums){ int k = nums.length; long lcm = 1; for(int j=0;j<k;j++){ if(nums[j]<lcm){ lcm = lcm/gcd(lcm,nums[j])*nums[j]; }else{ lcm = nums[j]/gcd(lcm,nums[j])*lcm; } } return lcm; } public static void main(String[] args) { Scanner cin = new Scanner(System.in); String line = cin.nextLine(); line = line.trim(); int machinesCount = Integer.parseInt(line); int[][] testCases = new int[machinesCount][]; for (int i = 0; i < machinesCount; i++) { line = cin.nextLine(); line = line.trim(); int w = Integer.parseInt(line); line = cin.nextLine(); line = line.trim(); int[] p = new int[w]; String[] tokens = line.split(" "); for (int j = 0; j < tokens.length; j++) { String token = tokens[j].trim(); if (token.length() > 0 && j < w) { p[j] = Integer.parseInt(token); } } testCases[i] = p; } for (int i = 0; i < machinesCount; i++) { int[] p = testCases[i]; long result = Main.solve(p); if(result<=1000000000){ System.out.println(result); }else{ System.out.println("More than a billion."); } } } }
以上两个都是AC解。
类似的一道求LCM题:http://acm.hdu.edu.cn/showproblem.php?pid=1019
该题只能用gcd的方法,才能AC(poj的题因为限制w ≤ 5所以质因数分解耗时不会太多):
import java.util.Scanner; /** * * @author ljs * 2011-06-23 * */ public class Main { public static long gcd(long m,long n){ m = (m<0)?-m:m; n = (n<0)?-n:n; while(n!=0){ long remainder = m%n; m = n; n = remainder; } return m; } public static long solve(int[] nums){ int k = nums.length; long lcm = 1; for(int j=0;j<k;j++){ if(nums[j]<lcm){ lcm = lcm/gcd(lcm,nums[j])*nums[j]; }else{ lcm = nums[j]/gcd(lcm,nums[j])*lcm; } } return lcm; } public static void main(String[] args) { Scanner cin = new Scanner(System.in); String line = cin.nextLine(); line = line.trim(); int testCasesNum = Integer.parseInt(line); int[][] testCases = new int[testCasesNum][]; for (int i = 0; i < testCasesNum; i++) { line = cin.nextLine(); line = line.trim(); int[] p = null; String[] tokens = line.split(" "); for (int j = 0,m=0; j < tokens.length; j++) { String token = tokens[j].trim(); if (j==0) { p = new int[Integer.parseInt(token)]; }else{ if (token.length() > 0 && m < p.length) { p[m++] = Integer.parseInt(token); } } } testCases[i] = p; } for (int i = 0; i < testCasesNum; i++) { int[] p = testCases[i]; long result = Main.solve(p); System.out.println(result); } } }