• [HNOI 2013]比赛


    Description

    沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联 赛共N支球队参加,比赛规则如下: 
    (1) 每两支球队之间踢一场比赛。 (2) 若平局,两支球队各得1分。 
    (3) 否则胜利的球队得3分,败者不得分。 
    尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分, 然后聪明的她想计算出有多少种可能的比赛过程。 
    譬如有3支球队,每支球队最后均积3分,那么有两种可能的情况:
     可能性1    可能性2 
    球队  A  B  C  得分   球队 A  B  C  得分 
    A        -  3  0  3             A     -  0  3  3 
    B        0  -  3  3             B    3  -  0  3 
    C        3  0  -  3            C    0  3  -  3 
    但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算 出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对109+7取模的结果

    Input

    第一行是一个正整数N,表示一共有N支球队。 接下来一行N个非负整数,依次表示各队的最后总得分。

    输入保证20%的数据满足N≤4,40%的数据满足N≤6,60%的数据满足N≤8,100%的数据 满足3≤N≤10且至少存在一组解。

    Output

    仅包含一个整数,表示答案对10^9+7取模的结果

    Sample Input

    4
    4 3 6 4

    Sample Output

    3

    题解

    我们令$f(l, r)$表示考虑$l$和$r$比赛,按$l$为主,若$l == r$,则$l++$。

    考虑直接爆搜的话,就是枚举当前的与之后的每一个比赛的结果是什么,但是复杂度很高。

    优化的话,考虑我枚举完一个的得分之后,剩下的状态打乱顺序不会影响最终结果,因为前面的贡献已经计算完毕了。

    那么我每次从小到大排序,并且把状态压起来,记忆化一下,就可以通过官方数据了,还有诸如鸡兔同笼和得分上限的剪枝也可以加。

     1 //It is made by Awson on 2017.10.11
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <cmath>
     7 #include <stack>
     8 #include <queue>
     9 #include <vector>
    10 #include <string>
    11 #include <cstdio>
    12 #include <cstdlib>
    13 #include <cstring>
    14 #include <iostream>
    15 #include <algorithm>
    16 #define LL long long
    17 #define Min(a, b) ((a) < (b) ? (a) : (b))
    18 #define Max(a, b) ((a) > (b) ? (a) : (b))
    19 #define sqr(x) ((x)*(x))
    20 using namespace std;
    21 const int MOD = 1000000007;
    22 
    23 int n, a[15];
    24 map<LL, int>mp[15];
    25 
    26 LL get_hash(int *a) {
    27     LL sum = 0;
    28     for (int i = 1; i <= n; i++)
    29         sum = sum*28+a[i];
    30     return sum;
    31 }
    32 int dfs(int *a, int l, int r) {
    33     if (3*(r-l) < a[l]) return 0;
    34     if (l == r) {
    35         if (l == n) return 1;
    36         int b[15]; for (int i = 1; i <= n; i++) b[i] = a[i];
    37         sort(b+1, b+n+1);
    38         LL tmp = get_hash(b);
    39         if (mp[l+1].count(tmp) == 1) return mp[l+1][tmp];
    40         return mp[l+1][tmp] = dfs(b, l+1, n);
    41     }
    42     int tol = 0;
    43     if (a[l] >= 3) {
    44         a[l] -= 3;
    45         (tol += dfs(a, l, r-1)) %= MOD;
    46         a[l] += 3;
    47     }
    48     if (a[l] >= 1 && a[r] >= 1) {
    49         a[l] -= 1, a[r] -= 1;
    50         (tol += dfs(a, l, r-1)) %= MOD;
    51         a[l] += 1, a[r] += 1;        
    52     }
    53     if (a[r] >= 3) {
    54         a[r] -= 3;
    55         (tol += dfs(a, l, r-1)) %= MOD;
    56         a[r] += 3;
    57     }
    58     return tol;
    59 }
    60 void work() {
    61     scanf("%d", &n);
    62     for (int i = 1; i <= n; i++)
    63         scanf("%d", &a[i]);
    64     sort(a+1, a+n+1);
    65     printf("%d
    ", dfs(a, 1, n));
    66 }
    67 int main() {
    68     work();
    69     return 0;
    70 }
  • 相关阅读:
    【BZOJ 3090】 树形DP
    【BZOJ 2323】 2323: [ZJOI2011]细胞 (DP+矩阵乘法+快速幂*)
    【BZOJ 1019】 1019: [SHOI2008]汉诺塔 (DP?)
    【BZOJ 3294】 3294: [Cqoi2011]放棋子 (DP+组合数学+容斥原理)
    【BZOJ 3566】 3566: [SHOI2014]概率充电器 (概率树形DP)
    【BZOJ 2121】 (字符串DP,区间DP)
    【BZOJ 4305】 4305: 数列的GCD (数论)
    【UOJ 179】 #179. 线性规划 (单纯形法)
    【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)
    【BZOJ 4027】 4027: [HEOI2015]兔子与樱花 (贪心)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7652956.html
Copyright © 2020-2023  润新知