【HNOI2013】比賽

題目

沫沫非常喜歡看足球賽,但因爲沉迷於射箭遊戲,錯過了最近的一次足球聯賽。此次聯賽共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.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章