[Hnoi2013]比赛
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 400 Solved: 172
[ Submit][ Status]
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
4 3 6 4
Sample Output
3
枚举每次比赛,记忆化就可以了。
maxn 和 maxm 打错了改蠢我了。。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 15;
const int maxm = 40100;
int next[maxm], head[maxm];
typedef long long LL;
LL f[maxm], s[maxm];
int n;
LL make(int a[]){
LL sum = 0;
for (int i = 0; i <= n; i ++) sum = sum * 30 + a[i];
return sum;
}
void demake(int a[], LL x){
for (int i = n; i >= 0; i --) a[i] = x % 30, x /= 30;
}
int hash(LL x){
int k = x % 30077;
for (int i = head[k]; i; i = next[i])
if (s[i] == x) return i;
return -1;
}
int tot;
int insert(LL x, LL v){
int k = x % 30077;
s[++ tot] = x, f[tot] = v;
next[tot] = head[k], head[k] = tot;
}
LL dfs0(LL k);
LL dfs1(int c[], int x, int y){
LL ans = 0;
if (y > n)
if (c[x] == 0){
int t[maxn];
for (int i = 1; i <= n; i ++) t[i] = c[i]; //
//这里千万不要直接用c[],因为回溯的时候还会用
sort(t + 1, t + n + 1); t[0] = x;
return dfs0(make(t));
}
else return 0;
c[x] -= 3;
if (c[x] >= 0 && c[y] >= 0) ans += dfs1(c, x, y + 1);
c[x] += 3;
c[y] -= 3;
if (c[x] >= 0 && c[y] >= 0) ans += dfs1(c, x, y + 1);
c[y] += 3;
c[x] -= 1; c[y] -= 1;
if (c[x] >= 0 && c[y] >= 0) ans += dfs1(c, x, y + 1);
c[x] += 1; c[y] += 1;
return ans;
}//枚举输赢
LL dfs0(LL x){
int tmp = hash(x);
if (tmp != -1) return f[tmp];
int c[maxn];
demake(c, x);
if (c[0] == n && c[n] == 0) return 1;
LL sum = dfs1(c, c[0] + 1, c[0] + 2);
insert(x, sum);
return sum;
} // 记忆化 c[0]表示处理多少
int a[maxn];
int main(){
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
printf("%d", dfs0(make(a)) % 1000000007);
return 0;
}