C♯の勉強

C♯4.0 で TopCoder の過去問を解きます。

TopCoder SRM 591: YetAnotherTwoTeamsProblem

最小のスキルの固定して、|skill| 分だけ動的計画法すると O(50 * 50 * 50 * 60000) でTLE。

スキルが高い順に足していくと、最後に足されたスキルが最小のスキルになる。
そのことを利用して、昇順からナップサップの動的計画法をしていく、いざ足し合わせるタイミングで、問題にある条件を満たした場合のみ答えに足していけばよい。計算量は O(50 * 60000) となり十分間に合う。

public class YetAnotherTwoTeamsProblem {
    public long count(int[] skill) {
        skill = skill.OrderByDescending(s => s).ToArray();
        long ans = 0;
        long sum = skill.Sum();

        long[] dp = new long[sum + 1];
        dp[0] = 1;
        foreach (var s in skill) {
            for (int j = dp.Length - 1; j >= 0; j--) {
                if (j - s < 0) continue;
                dp[j] += dp[j - s];
                if (j > sum - j && j - s < sum - j + s) ans += dp[j - s];
            }
        }
        return ans;
    }
}