您的位置:首页 > 其它

【HNOI2013】比赛

2015-12-25 12:45 134 查看

题目

沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联赛共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数组转成数时要排一个序,否则这样状态数会很大。

这样便很好的解决这个问题了。

[code]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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: