【HNOI2013】比赛

来源:互联网 发布:h3c 查看端口聚合 编辑:程序博客网 时间:2024/05/18 03:37

题目

沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联赛共N 支球队参加,比赛规则如下:

(1) 每两支球队之间踢一场比赛。

(2) 若平局,两支球队各得1 分。

(3) 否则胜利的球队得3 分,败者不得分。

尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分,然后聪明的她想计算出有多少种可能的比赛过程。

譬如有3 支球队,每支球队最后均积3 分,那么有两种可能的情况:
这里写图片描述

但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对10^9+7 取模的结果。

20%的数据满足N≤4;

40%的数据满足N≤6;

60%的数据满足N≤8;

100%的数据满足3≤N≤10且至少存在一组解。

分析

我们看到这题的条件,大概就能估计到这题的方向:搜索!
可是如何才能去优化这个搜索呢?
我们先写出一个比较简单的搜索,然后再剪枝!
dfs(x,a)表示我们已经打完1..x-1(及1..x-1中任意的i都和i+1..n打过一次了)
且状态为a,现在用a[0]去打x。
然后我们很明显的去枚举状态,然后转移就可以了。

其实这样的搜索已经是很优的了,但是这样搜我们会搜到很多重复的状态,怎么办呢?
哈希判重,把每次搜过的状态,直接加上它会产生的答案。

那么我们应该在什么时候才判重呢?

明显的,当确定了x,和a时后面的方案是可以确定的,所以我们从这个入手。
当然我们只能在打完了x的时候才去hash,而且有个优化,a数组转成数时要排一个序,否则这样状态数会很大。
这样便很好的解决这个问题了。

type arr=array[0..10] of longint;const mo=62304567;u=1000000007;var    n,i,j:longint;    a:array[0..10] of longint;    c:array[0..10] of int64;    ha:array[-1..mo,1..2] of longint;function hash(x:longint):longint;var k:longint;begin    k:=x mod mo;    while (ha[k,1]<>0)and(ha[k,1]<>x) do k:=(k+1)mod mo;    exit(k);end;function get(a:arr):longint;var i:longint;p:int64;begin p:=a[0];    for i:=1 to n do       for j:=i+1 to n do       if a[i]>a[j] then begin          a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];       end;    a[0]:=p;    for i:=1 to n do p:=(p+a[i]*c[i])mod mo;    exit(p);end;function dfs(x:longint;a:arr):longint;var i,o,p:longint;pe:boolean;begin    dfs:=0;    if a[a[0]]>(n-x+1)*3 then exit(0);    if x>n then begin       o:=get(a);       p:=hash(o);       if ha[p,1]<>0 then begin          exit(ha[p,2]);       end else begin          if a[0]<>n-1 then begin          if o=0 then o:=-1;          ha[p,1]:=o;inc(a[0]);dfs:=(dfs+dfs(a[0]+1,a))mod u;          ha[p,2]:=dfs;          end else begin pe:=false;          for i:=1 to n do if a[i]>0 then begin pe:=true;break;end;          if not pe then begin             ha[p,1]:=o;ha[p,2]:=1;exit(1);          end          else begin ha[p,1]:=o;ha[p,2]:=0;exit(0);end;          end;       end;exit;    end;   if a[a[0]]>=3 then begin dec(a[a[0]],3);dfs:=dfs+dfs(x+1,a);inc(a[a[0]],3);end;   if a[x]>=3 then begin dec(a[x],3);dfs:=dfs+dfs(x+1,a);inc(a[x],3);end;   if (a[x]>0)and(a[a[0]]>0) then begin dec(a[a[0]],1);dec(a[x],1);dfs:=dfs+dfs(x+1,a);inc(a[a[0]]);inc(a[x]);end;end;begin    readln(n);c[0]:=1;    for i:=1 to 10 do c[i]:=(c[i-1]*27)mod mo;    for i:=1 to n do read(a[i]);    for i:=1 to n do       for j:=i+1 to n do       if a[i]>a[j] then begin          a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];       end;    a[0]:=1;   writeln(dfs(2,a));end.
0 0
原创粉丝点击