[HNOI2013]比赛 搜索

[HNOI2013]比赛

搜索。

LG传送门

直接暴力有60,考场上写的60,结果挂成40。

考虑在暴力的同时加个记忆化,把剩下的球队数和每支球队的得分情况hash一下,每次搜到还剩\(t\)个队的时候就在哈希表里找一下,有就拿来算答案,没有就把这次的结果存进哈希表。复杂度\(O(\)能过\()\)

#include <cstdio>
#include <algorithm>
#include <unordered_map>
#define R register
#define I inline
#define L long long
using namespace std;
const int N = 13, B = 29, yyb = 1e9 + 7;
int a[N], b[N], f[N], sta[N], stp, n, t, k;
unordered_map <L, L> m;
I int cmp(int x, int y) { return x > y; }
L dfs(int x, int y) {
    if (x == n)
        return 1;
    if (f[x] + (n - y + 1) * 3 < a[x])
        return 0;
    L o = 0;
    if (y > n){
        R int i;
        for (i = x + 1; i <= n; ++i)
            b[i] = a[i] - f[i];
        sort(b + x + 1, b + n + 1);
        for (i = x + 1; i <= n; ++i)
            o = o * B + b[i];
        if (m.find(o) != m.end())
            return m[o];
        else
            return m[o] = dfs(x + 1, x + 2);
    }
    if (f[x] + 3 <= a[x] && k)
        f[x] += 3, --k, o += dfs(x, y + 1), f[x] -= 3, ++k;
    if (f[y] + 3 <= a[y] && k)
        f[y] += 3, --k, o += dfs(x, y + 1), f[y] -= 3, ++k;
    if (f[x] < a[x] && f[y] < a[y] && t)
        ++f[x], ++f[y], --t, o += dfs(x, y + 1), --f[x], --f[y], ++t;
    return o % yyb;
}
int main() {
    scanf("%d", &n), t = n * (n - 1) * 3 >> 1;
    for (R int i = 1; i <= n; ++i)
        scanf("%d", &a[i]), t -= a[i];
    sort(a + 1, a + n + 1, cmp), k = (n * (n - 1) >> 1) - t, printf("%I64d", dfs(1, 2));
    return 0;
}

posted @ 2019-01-21 16:12  newbiechd  阅读(104)  评论(0编辑  收藏  举报