BZOJ 2208 [Jsoi2010]连通数 tarjan缩点+bitset优化DP

来源:互联网 发布:在职研究生研修班 知乎 编辑:程序博客网 时间:2024/06/04 19:01

题意:链接

方法: tarjan缩点+bitset优化DP?

解析:

大爷教bitset找的题=.=;

缩点是肯定的啦

之后怎么搞呢?

可以写个O(n^3)的小暴力。

先来想这个暴力怎么写,缩完点之后重构这个图,然后维护个连通性,即某个连通块能否到另一个连通块,如果能到,则对答案的贡献是两个连通块的大小的乘积,这很显然,每个连通块内部又可以任意选出两点成为连通对,即c[x,2]*2,x为块的大小,题中又说某个点与其本身又可称为连通,所以答案还需加上n。

之后考虑怎么优化?

我们发现缩完点后该图变为个拓扑图,然后我们可以开bitset这种神奇的东西,对于每一个连通块开一个bitset,该块的bitset是其所有子块的bitset的或。这样的话递归搞下去,最终复杂度就变为了O(n332),可过。

代码:

#include <bitset>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 2010using namespace std;bitset<N>b[N];int n,cnt,tot,top,cntsq,ans,cnt2;char s[N];int head[N],head2[N];int deep[N];int low[N];int belong[N];int out[N];int in[N];int siz[N];int sta[N];int ins[N];int c[N][3];bool v[N];struct node{    int from,to,next;}edge[N*N],edge2[N*N];void get_c(){    c[1][0]=1,c[1][1]=1;    for(int i=2;i<=n;i++)    {        c[i][0]=1;        for(int j=1;j<=2;j++)            c[i][j]=c[i-1][j]+c[i-1][j-1];    }}void init(){    memset(head,-1,sizeof(head));    memset(head2,-1,sizeof(head2));    cnt=cnt2=1;    get_c();}void edgeadd(int from,int to){    edge[cnt].from=from;    edge[cnt].to=to;    edge[cnt].next=head[from];    head[from]=cnt++; }void edgeadd2(int from,int to){    edge2[cnt2].from=from;    edge2[cnt2].to=to;    edge2[cnt2].next=head2[from];    head2[from]=cnt2++;}void tarjan(int now,int fa){    v[now]=1;    deep[now]=low[now]=++tot;    sta[++top]=now,ins[now]=1;    for(int i=head[now];i!=-1;i=edge[i].next)    {        int to=edge[i].to;        if(to==fa)continue;        if(!deep[to])        {            tarjan(to,now);            low[now]=min(low[now],low[to]);        }else if(ins[to])low[now]=min(low[now],deep[to]);    }    if(deep[now]==low[now])    {        ++cntsq;        int t;        do        {            t=sta[top--];            ins[t]=0;            belong[t]=cntsq;            siz[cntsq]++;        }while(t!=now);    }}void dfs(int now){    v[now]=1;    for(int i=head2[now];i!=-1;i=edge2[i].next)    {        int to=edge2[i].to;        if(!v[to])        {            dfs(to);        }        b[now]|=b[to];    }    for(int i=1;i<=cntsq;i++)    {        if(b[now][i]&&now!=i)ans+=siz[now]*siz[i];    }}int main(){    scanf("%d",&n);    init();    for(int i=1;i<=n;i++)    {        scanf("%s",s+1);        for(int j=1;j<=n;j++)        {            if(s[j]-'0')            {                edgeadd(i,j);            }        }    }    for(int i=1;i<=n;i++)    {        if(!v[i])        {            tarjan(i,-1);        }    }    for(int i=1;i<=cntsq;i++)ans+=c[siz[i]][2],b[i][i]=1;    ans*=2;    for(int i=1;i<cnt;i++)    {        int fx=belong[edge[i].from],fy=belong[edge[i].to];        if(fx!=fy)        {            edgeadd2(fx,fy);            b[fx][fy]=1;            in[fy]++;        }    }    memset(v,0,sizeof(v));    for(int i=1;i<=cntsq;i++)    {        if(!in[i])        {            dfs(i);        }    }    printf("%d\n",ans+n);}
0 0
原创粉丝点击