TopCoder SRM 635 Div1 Easy: SimilarRatingGraph

解法

Nが400以下なので、N-1個の区間の長さと傾きを計算しておき、傾きが等しく、長さの倍率が等しい区間を出せば良い……がっ……ダメっ……!!誤差ゲーなので値が小さくなり過ぎないように気をつけなければならない。

コード

import java.util.ArrayList;
import java.util.Collections;

public class SimilarRatingGraph {

	public double maxLength(int[] date, int[] rating) {
		int N = date.length;
		ArrayList<Rate> rates = new ArrayList<>();
		for (int i = 0; i < N; i++) {
			rates.add(new Rate(rating[i], date[i]));
		}
		Collections.sort(rates);

		for (int i = 0; i < N; i++) {
			rating[i] = rates.get(i).rate;
			date[i] = rates.get(i).date;
		}

		double[] length = new double[N - 1];
		double[] grad = new double[N - 1];
		for (int i = 1; i < N; i++) {
			int dr = rating[i] - rating[i - 1];
			int dd = date[i] - date[i - 1];
			length[i - 1] = Math.sqrt((long) dr * dr + (long) dd * dd);// 長さ
			grad[i - 1] = (double) dr / dd;// 傾き
		}

		double max = 0;
		for (int i = 0; i < N - 1; i++) {
			for (int j = i + 1; j < N - 1; j++) {
				if (!same(grad[i], grad[j])) {
					continue;
				}
				double p = length[i] / length[j];
				int cnt = 0;
				while (j + cnt < N - 1 && same(grad[i + cnt], grad[j + cnt])
						&& same(p * length[j + cnt], length[i + cnt])) {
					cnt++;
				}

				double lengthI = 0;
				double lengthJ = 0;
				for (int k = 0; k < cnt; k++) {
					lengthI += length[i + k];
					lengthJ += length[j + k];
				}
				max = Math.max(max, Math.max(lengthI, lengthJ));
			}
		}

		return max;
	}

	private boolean same(double a, double b) {
		final double EPS = 1e-9;
		if (a + EPS < b || a - EPS > b) {
			return false;
		}
		return true;
	}

	class Rate implements Comparable<Rate> {
		int rate, date;

		public Rate(int r, int d) {
			this.rate = r;
			this.date = d;
		}

		@Override
		public int compareTo(Rate o) {
			return this.date - o.date;
		}
	}

}