難しくない問題なのに実装に時間を取られてしまった。深夜に開催されたのが悪いのだと思いたい。

D. Jerry’s Protest

解法

knapsack問題を重さの制約を利用して多項式時間でdpするあれに似たことをする。$O(n + a^2)$。単なる数え上げなので期待値のdpではない。

ボールに書かれた数の差の頻度表を作り、それを重ね合わせたものを作り、これらふたつをまとめて舐める。

実装

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
typedef long long ll;
using namespace std;
int main() {
    int n; cin >> n;
    vector<int> a(n); repeat (i,n) cin >> a[i];
    vector<ll> wins(*max_element(a.begin(), a.end()) - *min_element(a.begin(), a.end()) + 1);
    repeat (i,n) repeat (j,n) if (i != j and a[i] > a[j]) ++ wins[a[i] - a[j]];
    vector<ll> wins2(wins.size() * 2 + 1);
    repeat (i,wins.size()) repeat (j,wins.size()) wins2[i + j] += wins[i] * wins[j];
    ll cnt = 0;
    ll acc = 0;
    int j = 0;
    repeat (i, wins.size()) {
        cnt += wins[i] * acc;
        acc += wins2[j];
        ++ j;
    }
    printf("%.12f\n", cnt / pow(accumulate(wins.begin(), wins.end(), 0ll), 3));
    return 0;
}