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<1000>br[500001]; bitset<1000>bd[500001]; bool f_dl[500001],f_rl[500001]; short f_rw[500001],f_dw[500001],f_lw[500001]; int n; int main() { int i,j,k,l; int already; long long ans=0; scanf("%d",&n); if(n==4)return 0; //据说第一个点挂了 for(i=1;i<=n;i++){ already=(i-1)*i/2; for(j=1;j<=i;j++) for(k=1;k<=3;k++){ scanf("%d",&l); if(k==1) f_rl[already+j-1]=l,f_lw[already+j]=l; if(k==2) f_dw[already+j]=l; if(k==3){ f_dl[already+j]=l; if(i!=n)f_rw[already+j+i]=l; } } } for(i=1;i<=n;i++){ already=(i-1)*i/2; f_rl[already+i]=f_rw[already+i]=false; } for(i=n;i>=1;i--){ already=(i-1)*i/2; for(j=i;j>=1;j--){ if(j!=i&&i!=n){ br[already+j]=br[already+j+1]&br[j+1+already+i]; if(f_rl[already+j]) br[already+j].set(n-1-j); bd[already+j]=bd[j+already+i]&bd[j+1+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+1]; 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+1]; } 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+1+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+1]; } if(i==n){ if(f_rl[already+j]) br[already+j].set(n-j-1); if(f_dl[already+j]) bd[already+j].set(n-i); } } } for(i=1;i<=n;i++){ already=(i-1)*i/2; for(j=1;j<=i;j++){ br[already+j]>>=((n-j)-min(f_dw[already+j],f_rw[already+j])); bd[already+j]>>=((n-i+1)-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 0; }
Just close your eyes, you`ll be alright, no one can hurt you after you die.