zoukankan      html  css  js  c++  java
  • [HNOI2013]比赛

    Description

    Luogu3230
    BZOJ3139
    其实这道题和[CQOI2009](Luogu3154, BZOJ1306)重了。

    Solution

    搜索。枚举每场比赛的对手。要有两个剪枝:

    1. 可行性剪枝,就是如果每一场都赢也不能达到目标分数就剪掉。
    2. 记忆化,在要枚举下一个人的时候,可以记忆化一下:如果剩下的人的分数的情况已经算过了,就不用再算了,注意这个时候剩下的人是无序的(因为他们之间还没有比赛)。
      当然,为了方便,我们用扣分代替加分,最终分数为(0)即合法。

    Code

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <map>
    
    typedef unsigned long long ll;
    const int N = 11;
    const ll MOD = 1e9 + 7;
    
    std::map<ll, int> f;
    int a[N], b[N], n;
    
    inline ll hash(int x) {
        ll ans = x-1;
        for (int i = 1; i < x; ++i) ans = ans * 30 + b[i];
        return ans;
    }
    
    ll dfs(int x, int y) { // x和y大战 
        if (a[x] > (x-y) * 3) return 0; // 如果一直都赢也拿不到应有的分就gg 
        if (x == y) {
            if (x == 1) return 1; // 搜到最后一个人结束 
            for (int i = 1; i < x; ++i) b[i] = a[i];
            std::sort(b+1, b+x); // mark : 这里的上界
            ll hs = hash(x);
            return f.count(hs) ? f[hs] : f[hs] = dfs(x-1, 1);
        }
        ll ans = 0;
        if (a[x] >= 3) {
            a[x] -= 3;
            ans += dfs(x, y+1);
            a[x] += 3;
        }
        if (a[x] && a[y]) {
            a[x]--; a[y]--;
            ans += dfs(x, y+1);
            a[x]++; a[y]++;
        }
        if (a[y] >= 3) {
            a[y] -= 3;
            ans += dfs(x, y+1);
            a[y] += 3;
        }
        return ans;
    }
    
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        std::cout << dfs(n, 1);
        return 0;
    }
    
  • 相关阅读:
    不得不爱开源 Wijmo jQuery 插件集(6)【Popup】(附页面展示和源码)
    遗漏的知识点
    初识函数
    ==和is的区别 以及编码和解码
    函数的动态参数 及函数嵌套
    基本数据类型补充、set集合、深浅拷贝
    文件操作
    基本数据类型之“字典”
    建立自己的Servlet
    还原误删数据笔记
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/hnoi2013match.html
Copyright © 2011-2022 走看看