zoukankan      html  css  js  c++  java
  • BZOJ3515 : EvenPaths

    首先拓扑排序,并将障碍点按拓扑序平均分成两半。

    那么一条$0$到$1$的路径一定是形如:

    $0$->前一半点->后一半点->第一个后一半障碍点->后一半点->$1$。

    对于两边分别暴力枚举所有情况,设$f[i]$表示$0$出发到达$i$,且到$i$之前不经过任意一个后一半障碍点到达$i$的路径数;$g[i]$表示从$i$出发到$1$的路径数。

    那么枚举第一个后一半障碍点(或者是$1$),需要满足$f==1$且$g==1$,于是用FWT加速计算这个与卷积即可。

    时间复杂度$O(2^frac{Y}{2}(N+M))$。

    #include<cstdio>
    typedef long long ll;
    const int N=55,M=505;
    int n,cnt,m,ret,i,j,x,S,T;
    int is[N],g[N],v[M],nxt[M],ed,d[N],q[N],h,t;
    int id[N],vip[N],ban[N],f[N];
    ll F[1<<17],G[1<<17],ans;
    char a[N];
    void add(int x,int y){d[y]++;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void FWT(ll*a,int n){
      for(int d=1;d<n;d<<=1)for(int m=d<<1,i=0;i<n;i+=m)for(int j=0;j<d;j++){
        ll x=a[i+j],y=a[i+j+d];
        a[i+j]=x+y;
      }
    }
    void UFWT(ll*a,int n){
      for(int d=1;d<n;d<<=1)for(int m=d<<1,i=0;i<n;i+=m)for(int j=0;j<d;j++){
        ll x=a[i+j],y=a[i+j+d];
        a[i+j]=x-y;
      }
    }
    int main(){
      scanf("%d%s",&n,a);
      for(i=0;i<n;i++)if(a[i]=='?')is[i]=1;
      for(i=0;i<n;i++)for(scanf("%s",a),j=0;j<n;j++)if(a[j]=='Y')add(i,j);
      for(t=-1,i=0;i<n;i++)if(!d[i])q[++t]=i;
      while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(!(--d[v[i]]))q[++t]=v[i];
      for(i=0;i<n;i++)if(is[q[i]])id[m++]=q[i];
      cnt=m/2,ret=m-cnt+1;
      for(vip[1]=1,i=cnt;i<m;i++)vip[id[i]]=1;
      for(S=0;S<1<<cnt;S++){
        for(i=0;i<n;i++)ban[i]=f[i]=0;
        for(i=0;i<cnt;i++)if(S>>i&1)ban[id[i]]=1;
        for(i=0;i<n;i++){
          x=q[i];
          if(!x)f[x]=1;
          if(ban[x])f[x]=0;
          if(!f[x])continue;
          if(!vip[x])for(j=g[x];j;j=nxt[j])f[v[j]]^=1;
        }
        for(T=0,i=cnt;i<m;i++)if(f[id[i]])T|=1<<(i-cnt);
        if(f[1])T|=1<<(ret-1);
        F[T]++;
      }
      for(S=0;S<1<<(m-cnt);S++){
        for(i=0;i<n;i++)ban[i]=f[i]=0;
        for(i=0;i<(m-cnt);i++)if(S>>i&1)ban[id[i+cnt]]=1;
        for(i=n-1;~i;i--){
          x=q[i];
          if(x==1){f[x]=1;continue;}
          if(ban[x])continue;
          for(j=g[x];j;j=nxt[j])f[x]^=f[v[j]];
        }
        for(T=0,i=cnt;i<m;i++)if(f[id[i]])T|=1<<(i-cnt);
        if(f[1])T|=1<<(ret-1);
        G[T]++;
      }
      FWT(F,1<<ret),FWT(G,1<<ret);
      for(i=0;i<1<<ret;i++)F[i]*=G[i];
      UFWT(F,1<<ret);
      for(i=0;i<1<<ret;i++)if(__builtin_popcount(i)&1^1)ans+=F[i];
      return printf("%lld",ans),0;
    }
    

      

  • 相关阅读:
    GIT笔记
    C++新式类型转换
    C++ 静态链表基本算法实现
    C++ 顺序栈基本算法实现
    C++ 链栈 基本算法实现
    C++ 循环队列基本算法实现
    C++ 链队列基本算法实现
    C++优先级队列表基本算法实现
    C++单链表基本算法实现
    C++ 循环链表基本算法
  • 原文地址:https://www.cnblogs.com/clrs97/p/5768648.html
Copyright © 2011-2022 走看看