清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营

问题描述
  有一个正方形的地区,该地区特点鲜明:如果把它等分为N×N个小正方形格子的话,在每个格子内的任意地点的地表高度是相同的,并且是一个0到M之间的整数。正方形地区的外部被无限高的边界包围。
  该地区可能会有积水。经过多年的观察,人们发现了几个关于积水的重要规律:
  1. 每个格子要么完全没有积水,要么它内部的任意地点的水面高度都是相同的。并且水面高度一定大于地表高度。
  2. 每个格子的水面高度在0~M之间,并且一定是整数。
  3. 对于相邻(必须为边相邻)的两个格子,一定不会出现水自动从一个格子流向另一个格子的情况。也就是说,一定不能出现这两个格子都有水且水面高度不同,或者有水格子的水面比无水格子的地表要高的情况。
  例如,下面图中每个格子里有两个数a/b,说明该格子的地表高度是a,水面高度是b(均为海拔高度),而没有水的格子中b以“−”表示。则左边的情况是符合规律的,而右边的情况并不符合以上规律,因为水可以由2/4的格子流向3/−的格子。
清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营
  (图1)

  该地区水文站的工作人员小A想知道,该地区中有多少种不同的水位情况符合规律。你能回答他的这个问题吗?
输入格式
  输入文件的第一行包含两个正整数N和M。
  随后的N行,每行包含N个非负整数。其中第i+1行的第j个数表示该地区第i行第j列格子的地表高度。
输出格式
  输出文件只包含一个整数,即该地区符合规律的水位情况种数。
样例输入
4 3
1 1 1 1
1 2 2 2
1 2 3 3
1 2 3 2
样例输出
6
对样例的说明
  符合规律的水位情况有以下六种 :

清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营
数据规模和约定

清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营
 
 
好一个并查集
首先我们正着想,一开始都有模模糊糊的这个想法,就是划分区域,这几个区域的水一旦高于分界线的高度就会汇合,所以先计算出水位低于分界线的方案数,再算高于分界线的方案数
显然,低于这个高度的方案数是这几个区域的方案数的乘积,高于这个高度的方案数就是最高限制-这个高度,这几个区域的方案数可以递归做
但是递归又难写,时间上也不允许
所以我们从小到大枚举分界线的高度,把这个格子四周的区域合并,一直到整个区域,用并查集维护区域的信息
WA了好多次,原因是高精度数空间没开够,囧......
 const
maxn=;
s=;
fx:array[..]of longint=(,,-,);
fy:array[..]of longint=(,,,-);
type
point=record
x,y:longint;
end;
big=array[..]of int64;
var
a:array[..maxn,..maxn]of longint;
b:array[..maxn*maxn]of point;
f,h:array[..maxn*maxn]of longint;
ans:array[..maxn*maxn]of big;
n,m:longint; operator *(var a,b:big)c:big;
var
i,j:longint;
begin
fillchar(c,sizeof(c),);
for i:= to a[] do
for j:= to b[] do
inc(c[i+j-],a[i]*b[j]);
c[]:=a[]+b[]-;
for i:= to c[]- do
begin
inc(c[i+],c[i]div s);
c[i]:=c[i]mod s;
end;
while c[c[]]>=s do
begin
c[c[]+]:=c[c[]]div s;
c[c[]]:=c[c[]]mod s;
inc(c[]);
end;
end; procedure add(var a:big;b:longint);
var
i:longint;
begin
inc(a[],b);
i:=;
while a[i]>=s do
begin
inc(a[i+],a[i]div s);
a[i]:=a[i]mod s;
inc(i);
end;
if i>a[] then a[]:=i;
end; function calc(i,j:longint):longint;
begin
exit((i-)*n+j);
end; function find(x:longint):longint;
begin
if f[x]=x then exit(x);
f[x]:=find(f[x]);
exit(f[x]);
end; procedure swap(var x,y:point);
var
t:point;
begin
t:=x;x:=y;y:=t;
end; procedure sort(l,r:longint);
var
i,j,y:longint;
begin
i:=l;
j:=r;
y:=a[b[(l+r)>>].x,b[(l+r)>>].y];
repeat
while a[b[i].x,b[i].y]<y do
inc(i);
while a[b[j].x,b[j].y]>y do
dec(j);
if i<=j then
begin
swap(b[i],b[j]);
inc(i);
dec(j);
end;
until i>j;
if i<r then sort(i,r);
if j>l then sort(l,j);
end; procedure print(a:big);
var
i:longint;
k:int64;
begin
write(a[a[]]);
for i:=a[]- downto do
begin
k:=s div ;
while k> do
begin
if a[i]<k then write()
else break;
k:=k div ;
end;
write(a[i]);
end;
end; procedure main;
var
i,j,x,y:longint;
begin
read(n,m);
for i:= to n do
for j:= to n do
begin
read(a[i,j]);
h[calc(i,j)]:=a[i,j];
b[calc(i,j)].x:=i;
b[calc(i,j)].y:=j;
end;
sort(,n*n);
for i:= to n*n do
begin
f[i]:=i;
ans[i][]:=;
ans[i][]:=;
end;
for i:= to n*n do
for j:= to do
if (b[i].x+fx[j]>) and (b[i].x+fx[j]<=n) and (b[i].y+fy[j]>) and (b[i].y+fy[j]<=n) then
begin
x:=find(calc(b[i].x,b[i].y));
y:=find(calc(b[i].x+fx[j],b[i].y+fy[j]));
if (h[x]>=h[y]) and (x<>y) then
begin
add(ans[y],h[x]-h[y]);
ans[x]:=ans[x]*ans[y];
f[y]:=x;
end;
end;
add(ans[find()],m-a[b[n*n].x,b[n*n].y]);
print(ans[find()]);
end; begin
main;
end.
上一篇:清橙A1212:剪枝


下一篇:清橙 A1120 拦截导弹 -- 动态规划(最长上升子序列)