import java.io.IOException; import java.util.*; import org.apache.hadoop.fs.Path; import org.apache.hadoop.conf.*; import org.apache.hadoop.io.*; import org.apache.hadoop.mapreduce.*; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.input.TextInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; public class BarelyAcute { private static int limit = 25000000; public static class Map extends Mapper { public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { int k = Integer.valueOf(value.toString()); if (k == 0) { context.write(new IntWritable(k), new IntWritable(0)); return; } if (k > limit) { return; } ArrayList devs1 = getDevs(k); ArrayList devs2 = getDevs(k + 1); long product = (long) k * (long) (k + 1); for (int i = 0; i < devs1.size(); ++i) { // Find the first index j in devs2 for which // (devs1[i]*devs2[j])^2 >= product int beg = -1; int end = devs2.size(); while (end - beg > 1) { int mid = (end + beg) / 2; long temp = (long) devs1.get(i) * (long) devs2.get(mid); if (temp >= k + 1 || temp * temp >= product) { end = mid; } else { beg = mid; } } // add divisors while devs1[i]*devs2[j] <= limit for (int j = end; j < devs2.size(); ++j) { Long temp = (long) devs1.get(i) * (long) devs2.get(j); if (temp*2 + (long)2 * k + (long)1 > (long)limit) { break; } context.write(new IntWritable(k), new IntWritable(temp .intValue())); } } } private ArrayList getDevs(int x) { ArrayList res = new ArrayList(); // Store the divisors greater than the square root in this // array sorted in decreasing order. ArrayList big_devs = new ArrayList(); for (int u = 1; u * u <= x; ++u) { if (x % u == 0) { res.add(u); if (u * u != x) { big_devs.add(x / u); } } } // Add the divisors greater than the square root in the correct order. for (int i = big_devs.size() -1; i >=0; --i) { res.add(big_devs.get(i)); } // Now res holds all the divisors sorted in increasing order. return res; } } public static class Reduce extends Reducer { public void reduce(IntWritable key, Iterable values, Context context) throws IOException, InterruptedException { if (key.get() == 0) { context.write(key, new IntWritable((limit -1)/2)); return; } int number = 0; for (IntWritable val : values) { if (check(key.get(), val.get())) { number++; } } // context.write(key, new Text(res)); context.write(key, new IntWritable(number)); } private boolean check(long k, long sum) { long temp = k * (k + 1); long diff = temp / sum; diff *= 2; sum *= 2; long b = (sum - diff) / (long)2; long c = sum - b; long a = (long) 2 * k + (long)1; if (a + b <= c || b + c <= a || a + c <= b) { return false; } // Avoid counting solutions more than once. if (b%(long)2 == (long)1 && b < a) { return false; } return true; } // private String tos(long k, long sum) { // long temp = k * (k + 1); // long diff = temp / sum; // diff *= 2; // sum *= 2; // long b = (sum - diff) / 2; // long c = sum - b; // long a = (long) 2 * k + 1; // return a + " " + b + " " + c + " " ; // } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = new Job(conf, "BarelyAcute"); job.setOutputKeyClass(IntWritable.class); job.setOutputValueClass(IntWritable.class); job.setMapperClass(Map.class); job.setReducerClass(Reduce.class); job.setInputFormatClass(TextInputFormat.class); job.setOutputFormatClass(TextOutputFormat.class); job.setJarByClass(BarelyAcute.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); job.waitForCompletion(true); } }