bzoj1079

时间:2022-10-04 21:00:26

50%的数据很好考虑,基本的dp了

关键到了100%,如果用每种颜色有ci种这种常规的写法,显然5^15会爆空间

考虑到反过来,ci<=5, 15^5是不会爆空间的

又想到,每一种颜色,如果数量相同的话,其实是等效的。

这样我们不难想到用f[a,b,c,d,e,last]表示剩余颜色数量(就是还能刷木块的数目)为1,2,3,4,5的颜色种数为a,b,c,d,e时,且上一个位置用了剩余颜色数量为last的颜色有多少种方案

然后是实现的问题,弱弱的我想了半天,因为剩余数量对应的颜色种数是可增可减的,

所以我觉得通常以循环实现好像有点困难(好像也是可以写的,但太弱了……)

后来发现网上写的都是记忆化搜索,然后发现记忆化搜索实现起来比较容易;

其实记忆化搜索的效率基本上就等同于dp了

方程略复杂但是还是很很好想的

 const mo=;
var f:array[..,..,..,..,..,..] of int64;
    sum:array[..] of longint;
    i,n,m,x:longint; function ma(a,b:longint):longint;
  begin
    if a=b then exit() else exit();
  end; function search(a,b,c,d,e,last:longint):int64;
  var s:int64;
  begin
    if a+b+c+d+e= then   //颜色用完了
    begin
      f[a,b,c,d,e,last]:=;
      exit();
    end;
    if f[a,b,c,d,e,last]> then exit(f[a,b,c,d,e,last]);  //记忆化
    s:=;   //累加这个位置上是用颜色数量为几的方案
    if a> then s:=(s+(a-ma(last,))*search(a-,b,c,d,e,) mod mo) mod mo;
    if b> then s:=(s+(b-ma(last,))*search(a+,b-,c,d,e,) mod mo) mod mo;
//个转移是同理的,我就挑第二个说一下吧,首先当前位置如果用数量为2的b种颜色,显然每种颜色涂都能带来相同的方案数
//显然,用了一个剩余数量为2的颜色涂当前位置,到下一个位置,剩余数量为1的颜色种类数肯定多了一个,剩余数量为2的颜色种数肯定少了一个
//但是我们要考虑到,假如上一个位置用的是剩余数量为3的颜色涂的话,到了当前位置,上一个涂的剩余颜色数量变为2了,显然这个颜色是不能再涂这个位置的,要减去多算的方案(是不是废话有点多……)
    if c> then s:=(s+(c-ma(last,))*search(a,b+,c-,d,e,) mod mo) mod mo;
    if d> then s:=(s+(d-ma(last,))*search(a,b,c+,d-,e,) mod mo) mod mo;
    if e> then s:=(s+e*search(a,b,c,d+,e-,) mod mo) mod mo;
    f[a,b,c,d,e,last]:=s;  //记忆化
    exit(s);
  end; begin
  readln(m);
  for i:= to m do
  begin
    read(x);
    n:=n+x;
    inc(sum[x]);
  end;
  writeln(search(sum[],sum[],sum[],sum[],sum[],) mod mo);
end.