kmjp's blog

競技プログラミング参加記です

TopCoder SRM 669 Div2 Medium CombiningSlimes

SRM669に参加。Easyで(終わってみると不要だった)ResubmitするわMedium解けないわグダグダだったが、7Challenge決めて赤復帰。
http://community.topcoder.com/stat?c=problem_statement&pm=13947

問題

N個に分裂したスライムがおり、各サイズはA[i]である。
サイズがxとyの2つのスライムを合体させると、そのサイズx+yの1個のスライムになる。
その際、x*yのポイントが得られる。

N個のスライムを最適な順で合体させて1個にした場合、ポイントの最大値はいくつになるか。

解法

試してみると、合体順は関係ないことがわかる。
例えばA={a, b, c}で適当に連結させると、ab+bc+ca = (a(b+c) + b(c+a) + c(a+b))/2である。
もっと一般的に書くと、 \frac{1}{2} \times \sum_i (A_i*(sum(A)-A_i))である。

良く考えてみると、スライムを連結させる過程で元i番のスライムとj番のスライムは1回だけ合体するのでA[i]*A[j]が1回だけ最終ポイントに寄与することがわかる。
あとは上記式を求めるだけ。

class CombiningSlimes {
	public:
	int maxMascots(vector <int> a) {
		int tot=0;
		int sum=0;
		FORR(r,a) tot+=r;
		FORR(r,a) sum+=r*(tot-r);
		return sum/2;
	}
}

まとめ

これがわかっているとDiv1 Easyがむちゃくちゃ簡単。