bzoj1201: [HNOI2005]数三角形----递推+bitset

时间:2022-07-22 03:43:40

bzoj1201: [HNOI2005]数三角形----递推+bitset

bzoj1201: [HNOI2005]数三角形----递推+bitset

bzoj1201: [HNOI2005]数三角形----递推+bitset

bzoj1201: [HNOI2005]数三角形----递推+bitset

          -by  bzoj

http://www.lydsy.com/JudgeOnline/problem.php?id=1201



枚举所有交点,统计每个以每个点为顶点的正三角和和以每个点为左端点的反三角

计算正三角的方法是递推统计,

如果维护了每个点可以向左下和右下联通而不断开的长度,以及在这个长度内,有几个联通左右的没有断开的横边,

就可以得到正三角的个数了,

维护向左下右下延伸长度可以递推;

维护联通左右的横边个数也可递推;

递推时除了联通的横边的个数外,还需要横边的位置;

因为有了位置的话,可以将联通情况表示成一个01串;

这样某个点对应的01串可以表示为他下面两点的01串按位与;

这个点的01串应该比他下面两点的01串多一位;

多出来的这一位是他下面两点的联通情况;

最后统计答案时,

对每个点而言,在它向左下右下延伸的长度中取min,然后把01串中比这个min长的部分掐掉

然后统计1的个数,计入答案

反三角部分也是同理

然而这个递推是$n^3$的

(据说这个能过)

但所有的01串都可以用bitset完成,于是效率变成了$O({{n^3} \over {64}})$

于是就可以过n=1000了

代码:

洛谷第一个点挂了,所以要加上n=4的特判,

bzoj好像数组要开大点,

#include<cstdio>
#include<bitset>
using namespace std;
bitset<>br[];
bitset<>bd[];
bool f_dl[],f_rl[];
short f_rw[],f_dw[],f_lw[];
int n;
int main()
{
int i,j,k,l;
int already;
long long ans=;
scanf("%d",&n);
if(n==)return ;
//据说第一个点挂了
for(i=;i<=n;i++){
already=(i-)*i/;
for(j=;j<=i;j++)
for(k=;k<=;k++){
scanf("%d",&l);
if(k==)
f_rl[already+j-]=l,f_lw[already+j]=l;
if(k==)
f_dw[already+j]=l;
if(k==){
f_dl[already+j]=l;
if(i!=n)f_rw[already+j+i]=l;
}
}
}
for(i=;i<=n;i++){
already=(i-)*i/;
f_rl[already+i]=f_rw[already+i]=false;
}
for(i=n;i>=;i--){
already=(i-)*i/;
for(j=i;j>=;j--){
if(j!=i&&i!=n){
br[already+j]=br[already+j+]&br[j++already+i];
if(f_rl[already+j])
br[already+j].set(n--j);
bd[already+j]=bd[j+already+i]&bd[j++already+i];
if(f_dl[already+j])
bd[already+j].set(n-i);
if(f_rw[already+j])
f_rw[already+j]+=f_rw[already+j+];
if(f_lw[already+j])
f_lw[already+j]+=f_lw[already+j+i];
if(f_dw[already+j])
f_dw[already+j]+=f_dw[already+j+i+];
}
if(j==n&&i==n){
if(f_dl[already+j])
bd[already+j].set(n-i);
continue;
}
if(j==i){
bd[already+j]=bd[j+already+i]&bd[j++already+i];
if(f_dl[already+j])
bd[already+j].set(n-i);
if(f_lw[already+j])
f_lw[already+j]+=f_lw[already+j+i];
if(f_dw[already+j])
f_dw[already+j]+=f_dw[already+j+i+];
}
if(i==n){
if(f_rl[already+j])
br[already+j].set(n-j-);
if(f_dl[already+j])
bd[already+j].set(n-i);
}
}
}
for(i=;i<=n;i++){
already=(i-)*i/;
for(j=;j<=i;j++){
br[already+j]>>=((n-j)-min(f_dw[already+j],f_rw[already+j]));
bd[already+j]>>=((n-i+)-min(f_dw[already+j],f_lw[already+j]));
k=br[already+j].count();
ans+=(long long )k;
k=bd[already+j].count();
ans+=(long long )k;
}
}
printf("%lld\n",ans);
return ;
}