zoukankan      html  css  js  c++  java
  • 水题选讲

    duliu

    点就完了
    因为标签是虚树所以考虑树
    看到56的数据点,发现图是棵树,于是快乐地把56数据点作为切入点
    其实就是么有上司的舞会是吧

    [f[x][0]=Σf[v][0]+f[v][1] ]

    [f[x][1]=Σf[v][0] ]

    那么我们对于一个图就直接地把图破成树好了,枚举每条边是否选择,强行跑树DP,但是边太多了所以必死无疑
    但是考虑标签是虚树但是看到数据,(m)只比(n)(11),通过虚树可以让枚举次数大大降低,另外,因为每次只会有一些特殊的点(就是环上的点)对答案做出贡献,可以用虚树来优化
    而最大的(m leq n+11),我们可以把这些多出来的点拎出来构建虚树,并在虚树上DP

    注意,接下来是本题最恶心的地方

    我们假设有下面这条链(这条链将被用来建立虚树,我们会在这条边上DP)
    graph.png
    dp数组向上传递是有一定规律的

    [f[5][0]=prod f[6][0]+f[6][1] ]

    [f[5][1]=prod f[6][0] ]

    [f[4][0]=prod f[5][0]+f[5][1] ]

    [即 ]

    [f[4][0]=prod (f[6][0]+f[6][1])+f[6][0] ]

    [f[4][1]=prod f[6][0]+f[6][1] ]

    [f[3][0]=prod f[4][0]+f[4][1] ]

    [f[3][0]=prod ((f[6][0]+f[6][1])+f[6][0])+(f[6][0]+f[6][1]) ]

    [f[3][1]=prod f[4][0] ]

    [f[3][1]=prod f[6][0]+f[6][1]+f[6][0] ]

    我们发现

    [f[6][0] 和 f[6][1] ]

    每次递归会传递一次这玩意,而虚树边上的点是固定的,所以这两个玩意被加上的次数是可以递归处理出来的
    所以我们得到这个方程(v是x在虚树上的父亲)

    [f[x][1]=k0[v][1]*f[v][0]+k1[v][1]*f[v][1] ]

    [f[x][0]=k0[v][0]*f[v][0]+k1[v][0]*f[v][0] ]

    预处理出k就能舒服DP
    而预处理的方法比较坑
    我们先考虑x原树上的一个儿子t
    设在添加t(树DP的时候)前(f[x][1])(ovo[x][1])

    [f[x][1]=ovo[x][1]*[(f[v][0]*k1[v][0])+(f[v][1]*k0[v][1])] ]

    所以考虑刚才对k数组的理解

    [k1[v][0]=ovo[x][1]*k0[v][0] ]

    最后梳理下dp的流程

    预处理出k数组
    每次暴力枚举加入了哪些非树边
    树DP

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define N 100020 
    #define mod 998244353
    using namespace std;
    ll head[N],hh[N],dfn[N],dep[N],f[25][N],ff[N][3],k0[N][3],k1[N][3],dp[N][3];
    ll b[25],bj[N],in[N],g[N][3],p[N],st[N];
    ll n,m,cnt=1,ret,tmp,T,tt,tp,ans;
    bool vis[N],en[N*2];
    
    struct Tuck{
          ll u1,v1;
    }tr[N];
    
    struct The_World{
          ll to,nxt;
    }q[N*10];
    
    struct Star_Platinum{
          ll v,nx;
    }e[N*10];
    
    bool cmp(ll x,ll y){
          return dfn[x]<dfn[y];
    }
    
    void add(ll u,ll v){
          q[++cnt].to=v,q[cnt].nxt=head[u];
          head[u]=cnt;
          q[++cnt].to=u,q[cnt].nxt=head[v];
          head[v]=cnt;
    }
    
    void edd(ll u,ll v){
    	e[++ret].v=v,e[ret].nx=hh[u];
    	hh[u]=ret;
    }
    
    void dfs(ll x,ll fa){
          dfn[x]=++tmp;
          dep[x]=dep[fa]+1;
          vis[x]=1;
          for(ll i=1;i<=20&&f[i-1][x];i++){
                f[i][x]=f[i-1][f[i-1][x]];
          }
          for(ll i=head[x];i;i=q[i].nxt){
                ll v=q[i].to;
                if(v!=fa){
                      if(!vis[v]){
                            f[0][v]=x;
                            dfs(v,x);
                      }
                      else {
                            T++;
                            tr[T].u1=x,tr[T].v1=v;
                            en[i]=en[i^1]=1;
                      }
                }
          }
    }
    
    ll LYCA(ll x,ll y){
          if(dep[x]<dep[y])swap(x,y);
          for(ll i=20;i>=0;i--){
                if(dep[f[i][x]]>=dep[y]){
                      x=f[i][x];
                }
                if(x==y)return x;
          }
          for(ll i=20;i>=0;i--){
                if(f[i][x]!=f[i][y]){
                      x=f[i][x];
                      y=f[i][y];
                }
          }
          return f[0][x];
    }
    
    void build_vtree(ll x){
          if(tt==1){
                st[++tt]=x;
                return ;
          }
          ll lca=LYCA(st[tt],x);
          while(tt>1&&dfn[st[tt-1]]>=dfn[lca]){
                edd(st[tt-1],st[tt]);
                tt--;
          }
          if(st[tt]!=lca){
                in[lca]=1;
                edd(lca,st[tt]);
                st[tt]=lca;
          }
          st[++tt]=x;
    }
    
    void dp1(ll x,ll o){
          ff[x][0]=ff[x][1]=1;
          in[x]=1;
          for(ll i=head[x];i;i=q[i].nxt){
                ll v=q[i].to;
                if(v==f[0][x]||v==o||in[v]||en[i])continue;
                dp1(v,o);
                ff[x][0]=ff[x][0]*(ff[v][0]+ff[v][1])%mod;
                ff[x][1]=ff[x][1]*ff[v][0]%mod;
          }
    }
    
    void getk(ll x,ll y){
          k0[x][0]=1,k1[x][1]=1;
          for(ll i=x;f[0][i]!=y;i=f[0][i]){
                dp1(f[0][i],i);
                ll t0=k0[x][0],t1=k1[x][0];
                k0[x][0]=ff[f[0][i]][0]*(k0[x][0]+k0[x][1])%mod;
                k1[x][0]=ff[f[0][i]][0]*(k1[x][0]+k1[x][1])%mod;
                k0[x][1]=ff[f[0][i]][1]*t0%mod;
                k1[x][1]=ff[f[0][i]][1]*t1%mod;
          }
    }
    
    void yu_work(ll x){
          for(ll i=hh[x];i;i=e[i].nx){
                ll v=e[i].v;
                yu_work(v),getk(v,x);
          }
          ff[x][0]=ff[x][1]=1;
          for(ll i=head[x];i;i=q[i].nxt){
                ll v=q[i].to;
                if(in[v]||en[i]||v==f[0][x])continue;
                dp1(v,0);
                ff[x][0]=ff[x][0]*(ff[v][0]+ff[v][1])%mod;
                ff[x][1]=ff[x][1]*ff[v][0]%mod;
          }
    }
    
    void DP2(ll x){
          g[x][0]=ff[x][0],g[x][1]=ff[x][1];
          for(ll i=hh[x];i;i=e[i].nx){
                ll v=e[i].v;
                if(v!=f[0][x]){
                      DP2(v);
                      ll f0=(k0[v][0]*g[v][0]%mod+k1[v][0]*g[v][1]%mod)%mod;
                      ll f1=(k0[v][1]*g[v][0]%mod+k1[v][1]*g[v][1]%mod)%mod;
                      g[x][0]=g[x][0]*(f0+f1)%mod;
                      g[x][1]=g[x][1]*f0%mod;
                }
          }
          if(bj[x]==1)g[x][0]=0;
          if(bj[x]==-1)g[x][1]=0;
    }
    
    int main(){
          scanf("%lld%lld",&n,&m);
          for(ll i=1;i<=m;i++){
                ll a1,a2;
                scanf("%lld%lld",&a1,&a2);
                add(a1,a2);
          }
          dfs(1,0);
          for(ll i=1;i<=T;i++){
                if(!in[tr[i].u1])in[tr[i].u1]=1,p[++tp]=tr[i].u1;
                if(!in[tr[i].v1])in[tr[i].v1]=1,p[++tp]=tr[i].v1;
          }
          sort(p+1,p+1+tp,cmp);
          st[tt=1]=1;
          for(ll i=1;i<=tp;i++){
                if(p[i]==1)continue;
                build_vtree(p[i]);
          }
          while(tt>1){
                edd(st[tt-1],st[tt]);
                tt--;
          }
          yu_work(1);
          b[1]=1;
          for(ll i=2;i<=tp+1;i++)b[i]=b[i-1]*2;
          for(ll i=0;i<b[tp+1];i++){
                for(ll j=1;j<=tp;j++){
                      if(i&b[j])bj[p[j]]=1;
                      else bj[p[j]]=-1;
                }
                bool pool=0;
                for(ll j=1;j<=T;j++){
                    if(bj[tr[j].u1]==1&&bj[tr[j].v1]==1){
                          pool=1;break;
                    }
                }
              if(pool)continue;
              DP2(1);
              ans=(ans+(g[1][0]+g[1][1])%mod)%mod;
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    nodeType 节点简介
    Hamming Codes
    Preface Numbering(还没好好看USACO的解答)
    位运算常见应用即ACM题优化实例
    Dynamic Programming(动态规划)
    operator new & new operator
    资料记录
    Ordered Fractions
    Healthy Holsteins
    Sorting A ThreeValued Sequence
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/13405780.html
Copyright © 2011-2022 走看看