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;
}

 

posted @ 2017-10-12 14:45  F.W.Nietzsche  阅读(372)  评论(0编辑  收藏  举报