(ssl1960)2009年东莞市信息学特长生测试题 开发区规划

2009年东莞市信息学特长生测试题 开发区规划

Description

小王是D市主管经济的副市长,由于经济发展的需要,要在D市组建一个高新技术开发区,经过研究,规划局在D市的东部划出了一块土地作为开发区选址。这块土地是一块矩形平原,小王准备在上面修建一些建筑。为了规划方便,他将矩形划分成N*M格。棘手的是,这块土地有些历史文化遗址散布在某些格子内,这些历史文化遗址是万万不能拆除的,否则将激起民愤,小王深知这一点,因此,他的新建筑在选址时要避开这些格子。
  假设新的建筑物有P种规格,每种建筑物都是正方形的,占地为Ti*Ti格 (1<=i<=P)。小王想知道对于每种规格的建筑,有多少种不同的合适选址方案(一种合适的选址方案指的是在该建筑所占的正方形区域内不存在有历史文化遗址的格子)。现在请你来当小王的秘书 帮他完成这个光荣而艰巨的任务。

Input

  从文件d.in读入数据,输入文件第一行包含三个数,分别代表N,M,P (1<=N,M<=2000,1<=P<=1000)。随后的n行,每行有m个0或1(1表示该格为空地,0表示该格有历史文化遗址)。接下来的P行每行有一个整数Ti (1

Output

  结果输出到文件d.out中,共有P行,每行一个整数,第i行的数代表边长为Ti的建筑物选址方案数。

Sample Input

4 4 2
1011
1111
1110
1110
2
3

Sample Output

5
1

Source

elba

题解:

   先看一下本题的范围,输入为2000*2000。看似很小,但如果直接枚举的话就是2000^3=80e(把每种边长的正方形都枚举一遍)。这样做就会超时(TLE),所以我们要剪下枝~(づ ̄3 ̄)づ
   我们以所有点作为右下角,求出最大能拓展的正方形的边长,最后累加(如果这个位置能拓展边长为5的正方形,它就一定能拓展边长为4(1≤x≤5)的正方形)
   首先我们先处理第一行,因为第一行无法向左上拓展,所以方便我们初始化和记录边长为1的正方形
   然后就处理后面几行就行了,不过要注意判断!例如i点可以向上拓展3个点,但它只能向左拓展2个点,由于它只能拓展正方形,所以它最多只能拓展边长为2的正方形!(否则顶多是矩形)

PS:

   x[i]为在第i个点时可以向x轴方向拓展x[i]个长度(靠前一个来更新),y[i]也以此类推。z[i]存放当前这个点最大能拓展的正方形数(靠对角线来更新),f[i]为以i为边长的正方形有f[i]个

var
 x,y,z,f:array[0..2001]of longint;
 n,m,p,t,i,j:longint;
 s:ansistring;
function min(a,b:longint):longint;
begin
 if a<b then exit(a);
 exit(b);
end;
begin
 read(n,m,p);
 readln;
 read(s);
 for i:=1 to m do
  if s[i]='0' then begin x[i]:=0; y[i]:=0; end
              else
               begin
                x[i]:=x[i-1]+1;//拓展~
                inc(y[i]);
                z[i]:=1;
                inc(f[1]);//第一行只能拓展边长为1的正方形
               end;
 for i:=2 to n do
  begin
   readln;
   read(s);
   for j:=1 to m do
    if s[j]='0' then begin x[j]:=0; y[j]:=0; end
                else begin x[j]:=x[j-1]+1; inc(y[j]); end;
   for j:=m downto 1 do
    if s[j]='0' then z[j]:=0//判断
                  else
                   begin
                    z[j]:=z[j-1]+1;
                    z[j]:=min(z[j],x[j]);//找合法的正方形
                    z[j]:=min(z[j],y[j]);
                    inc(f[z[j]]);
                   end;
  end;
 for i:=min(n,m) downto 1 do inc(f[i],f[i+1]);//累加
 for i:=1 to p do
  begin
   readln(t);
   writeln(f[t]);
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值