1201: [HNOI2005]数三角形 - BZOJ
2014-03-19 09:05
183 查看
Description Input 大三角形的所有短边可以看成由(n+1)*n/2个单位三角形的边界组成。如下图的灰色三角形所示。其中第1排有1个灰色三角形,第2排有2个灰色三角形,……,第n排有n个灰色三角形。所以输入格式是这样规定的:输入第一行为正整数n,其中1<=n<=1000,表示大三角形每边的长度。接下来的n行,第i+1行有i组数,从左到右每组数描述一个三角形,每组数都有3个数,这3个数非0即1,表示对应的短边是否被删除,0表示已被删除,1表示未被删除,依次按照三角形的左、右、下边的顺序来描述。所以第i+1行有3i个数,每个数是0或1 Output 仅包含一个整数T,表示有多少个三角形的边界都没有被删除。 Sample Input 5 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 Sample Output 19
统计有多少个三角形
枚举底边所在的直线
对于一个三角形,它的条件是底边是实线,左右两边要比底边长
我们先预处理出exl和exr,分别表示往左上最多延伸多长,往右上最多延伸多长
对于底边两点i和j,i<j
它需要满足的条件是(实线我们可以直接一段一段的处理)
j-i<=exr[i],j-i<=exl[j]
所以j<=exr[i]+i,j-exl[j]<=i
然后我们先把j-exl[j]排一个序,从小到大枚举i,加入j-exl[j]<=i的点(即a[j]++),注意要把j<=i的减掉
a[i]数组用树状数组维护,再统计a数组中[1..exr[i]+i]的和就可以了
一开始不知道,所以我把每一个j看成一个平面上的点,坐标为(j,j-exl[j]),枚举i,统计横坐标小于等于exr[i]+i且纵坐标小于等于i的点
用二维树状数组维护这个和,然后过了
这里就只贴二维的那个了(第一种方法没有写)
const maxn=1010; var tri:array[0..maxn,0..maxn,1..3]of integer; exl,exr,c:array[0..maxn,0..maxn]of integer; n,ans:longint; function max(x,y:longint):longint; begin if x>y then exit(x); exit(y); end; function min(x,y:longint):longint; begin if x<y then exit(x); exit(y); end; procedure init; var i,j:integer; begin read(n); for i:=1 to n do for j:=1 to i do read(tri[i,j,1],tri[i,j,2],tri[i,j,3]); end; function lowbit(x:longint):longint; begin exit(x and -x); end; procedure add(x,y,z:longint); var h:longint; begin while x<=n+1 do begin h:=y; while h<=n+1 do begin inc(c[x,h],z); h:=h+lowbit(h); end; x:=x+lowbit(x); end; end; function sum(x,y:longint):longint; var h:longint; begin sum:=0; while x>0 do begin h:=y; while h>0 do begin inc(sum,c[x,h]); h:=h-lowbit(h); end; x:=x-lowbit(x); end; end; procedure get; var h,l,r,i:longint; begin for h:=1 to n do begin l:=1; while l<=h do begin while (tri[h,l,3]=0)and(l<=h) do inc(l); if l>h then break; r:=l+1; while tri[h,r,3]=1 do inc(r); for i:=l to r do add(i,max(1,i-exl[h,i]),1); for i:=l to r do begin add(i,max(1,i-exl[h,i]),-1); inc(ans,sum(min(n+1,exr[h,i]+i),i)); end; l:=r+1; end; end; end; procedure work; var i,j:longint; begin for i:=1 to n do for j:=1 to i do begin if tri[i,j,1]=1 then exr[i,j]:=exr[i-1,j]+1; if tri[i,j,2]=1 then exl[i,j+1]:=exl[i-1,j]+1; end; get; for i:=1 to n do for j:=1 to i+1 do begin exl[i,j]:=0; exr[i,j]:=0; end; for i:=n downto 1 do for j:=1 to i do begin if tri[i,j,1]=1 then exl[i-1,j]:=exl[i,j]+1; if tri[i,j,2]=1 then exr[i-1,j]:=exr[i,j+1]+1; end; get; write(ans); end; begin init; work; end.
View Code
相关文章推荐
- bzoj1201: [HNOI2005]数三角形
- BZOJ 1201: [HNOI2005]数三角形
- [BZOJ1201][HNOI2005]数三角形(树状数组)
- bzoj 1202: [HNOI2005]狡猾的商人 并查集好题
- 【BZOJ 1202】 [HNOI2005]狡猾的商人
- [BZOJ1202] [HNOI2005]狡猾的商人
- 【BZOJ 1202】 [HNOI2005]狡猾的商人 (加权并查集)
- bzoj 1202: [HNOI2005]狡猾的商人(并查集+前缀和)
- 【bzoj1202】[HNOI2005]狡猾的商人
- 【BZOJ1202】【HNOI2005】狡猾的商人
- 狡猾的商人 [bzoj1202,HNOI2005]
- bzoj1202 [ HNOI2005 ] --带权并查集
- bzoj 1202: [HNOI2005]狡猾的商人
- [BZOJ]1202: [HNOI2005]狡猾的商人 带权并查集
- BZOJ1202 [HNOI2005]狡猾的商人 并查集+前缀和
- bzoj1206 [HNOI2005]虚拟内存
- [BZOJ 1202][HNOI2005]狡猾的商人(并查集+前缀和)
- 1199: [HNOI2005]汤姆的游戏 - BZOJ
- BZOJ 1206 [HNOI2005] 虚拟内存 题解与分析
- BZOJ 1202: [HNOI2005]狡猾的商人 并查集