[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 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/7652956.html