jzoj 高中 3505——积木
Description
小A正在搭积木。有N个位置可以让小A使用,初始高度都为0。小A每次搭积木的时候,都会选定一个拥有相同高度的区间[A..B],然后将位置[A+1..B-1]上的所有积木的高度加一。不幸的是,小A把积木搭好之后没多久,小A调皮的弟弟就将其中若干个位置上的积木弄倒了。小A想知道他原来的积木是如何摆放的,所以他求助于你,请你告诉他原来有多少种可能的摆法。 
 
Input 
第一行为一个正整数N,表示小A有N个位置。 
第二行有N个由空格分隔的整数Hi,表示第i个位置的积木高度。-1表示这个位置上的积木已经被弄倒了。
Output 
唯一的一行,输出包括可能的摆法mod 1,000,000,007的结果。
Sample Input 
输入1: 
3 
-1 2 -1
输入2: 
3 
-1 -1 -1
输入3: 
6 
-1 -1 -1 2 -1 -1
Sample Output 
输出1: 
0
输出2: 
2
输出3: 
3
Data Constraint 
对于50%的数据  1<=N<=1000 -1<=Hi<=1000 
对于80%的数据  1<=N<=10000 
对于100%的数据 1<=N<=20000 -1<=Hi<=10000
dp水法: 
设f[i,j]为第i个数,高度为j的方案数,有  
f[i,j]=sum(f[i-1,j-1],f[i-1,j],f[i-1,j+1])  
如果a[i]没有被破坏,那就除f[i,a[i]]外的状态都不合法。  
暴力跑一边,会超一点时。把每次mod,改为统计10次取一次mod就不会超时了。  
那么如果直接这样做,空间绝对会爆,因为只记录上一次那么开一个滚动数组就行了
代码:
const mo=1000000007;
var n,i,m,j:longint;
    a,k:array[0..20001]of longint;
    f:array[0..1,-1..20001]of int64;
begin
  assign(input,'brick.in');
  assign(output,'brick.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do read(a[i]);
  if (a[i]>0) then
    begin
      writeln(0);
      close(input);
      close(output);
      halt; 
    end;
  m:=n div 2+1;
  for i:=1 to n do if i<m then k[i]:=i-1 else k[i]:=n-i;
  f[1,0]:=1;
  for i:=2 to n do
    begin
      fillchar(f[i and 1],sizeof(f[i and 1]),#0);
      if a[i]=-1 then
        begin
          if i mod 10=0 then for j:=0 to k[i] do f[i and 1,j]:=(f[(i-1) and 1,j-1]+f[(i-1) and 1,j]+f[(i-1) and 1,j+1]) mod mo
          else for j:=0 to k[i] do f[i and 1,j]:=f[(i-1) and 1,j-1]+f[(i-1) and 1,j]+f[(i-1) and 1,j+1];
        end
      else f[i and 1,a[i]]:=(f[(i-1) and 1,a[i]-1]+f[(i-1) and 1,a[i]]+f[(i-1) and 1,a[i]+1]) mod mo;
    end;
  writeln(f[n and 1,0] mod mo);
  close(input);
  close(output);
end.
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号