bzoj 3139: [Hnoi2013]比赛

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取模的结果

solution

我是个xlb,这个题目显然需要记忆化,很久以前yy出hash DP一直没用得上,这题显然可以用,我的转移十分作死,转移是唯一的,记忆化没有什么用,其实只需要hash后面的队伍即可,其他基础剪枝看代码,另外队伍是等价的,所以拥有相同剩余分数的队伍是一样的,我们可以默认分数从小到大排序,这样可以减少状态

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=15,mod=1e9+7;
int n,a[N],m=0,res[N];
struct node{
   int x,y;
}e[N*N];
map<ll,ll>s;
long long ans=0;
il bool check(){
   for(RG int i=1;i<=n;i++)
      if(a[i])return false;
   return true;
}
il bool judge(){
   for(RG int i=1;i<=n;i++)
      if(3*res[i]<a[i])return true;
   return false;
}
int b[N];
il ll query(int x){
   ll tot=x;int l=0;
   for(int i=x+1;i<=n;i++)b[++l]=a[i];
   sort(b+1,b+l+1);
   for(int i=1;i<=l;i++)
      tot=tot*28+b[i];
   return tot;
}
il int dfs(int i){
   if(i==m+1){
      if(check())return 1;
      return 0;
   }
   if(judge())return 0;
   ll li;RG int x=e[i].x,y=e[i].y;ll ans=0;
   if(e[i].x!=e[i-1].x){
      li=query(e[i-1].x);
      if(s.count(li))return s[li];
   }
   res[x]--;res[y]--;
   if(a[x]>=3)a[x]-=3,ans+=dfs(i+1),a[x]+=3;if(ans>=mod)ans-=mod;
   if(a[y]>=3)a[y]-=3,ans+=dfs(i+1),a[y]+=3;if(ans>=mod)ans-=mod;
   if(a[x] && a[y])a[x]--,a[y]--,ans+=dfs(i+1),a[x]++,a[y]++;
   res[x]++;res[y]++;
   if(ans>=mod)ans-=mod;
   if(e[i].x!=e[i-1].x)s[li]=ans;
   return ans;
}
void work()
{
   scanf("%d",&n);
   for(int i=1;i<=n;i++)scanf("%d",&a[i]);
   sort(a+1,a+n+1);
   for(int i=1;i<=n;i++)
      for(int j=i+1;j<=n;j++)
         e[++m].x=i,e[m].y=j;
   for(int i=1;i<=n;i++)res[i]=n-1;
   cout<<dfs(1)<<endl;
}
 
int main(){work();return 0;}
posted @ 2017-10-16 15:51  PIPIBoss  阅读(154)  评论(0编辑  收藏  举报