zoukankan      html  css  js  c++  java
  • 【题解】Luogu P3349 [ZJOI2016]小星星

    原题传送门

    我们考虑设(dp_{i,j})表示树上的点(i)在图上对应的点为(j)(i)和子树对应在图上的方案数

    (dp_{u_i}=prod_{v in u.son} dp_{v,j}*w[i][j])(w[i][j]表示在图中(i)(j)是否连通)

    这个dp的复杂度是(O(n^3)),但是会发现它会多算答案,因为这个算法有可能会将多个树上的点对应到一个图上的点

    我们珂以二进制枚举,枚举哪些图上的点参与dp,按照容斥原理加减,这样就珂以算出答案,复杂度为(O(2^n n^3))

    #include <bits/stdc++.h>
    #define ll long long
    #define N 20
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    struct edge{
        int to,next;
    }e[N<<1];
    int head[N],cnt=0;
    inline void add(register int u,register int v)
    {
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
    }
    int n,m,w[N][N],ban[N],vis[N];
    ll f[N][N],ans;
    inline void dfs(register int x)
    {
        vis[x]=1;
        for(register int i=1;i<=n;++i)
            f[x][i]=1;
        for(register int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(vis[v])
                continue;
            dfs(v);
            for(register int j=1;j<=n;++j)
            {
                ll sum=0;
                for(register int k=1;k<=n;++k)
                    sum+=f[v][k]*(w[k][j]&ban[k]&ban[j]);
                f[x][j]*=sum;
            }
        }
    }
    int main()
    {
        n=read(),m=read();
        for(register int i=1;i<=m;++i)
        {
            int u=read(),v=read();
            w[u][v]=w[v][u]=1;
        }
        for(register int i=1;i<n;++i)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        for(register int k=1,siz;k<=(1<<n)-1;++k)
        {
            siz=n;
            for(register int i=1;i<=n;++i)
                ban[i]=0;
            for(register int i=1,p=k;p;p>>=1,++i)
                ban[i]=p&1,siz-=p&1;
            for(register int i=1;i<=n;++i)
                vis[i]=0;
            dfs(1);
            ll cnt=0;
            for(register int i=1;i<=n;++i)
                cnt+=f[1][i];
            if(siz%2)
                ans-=cnt;
            else
                ans+=cnt;
        }
        write(ans);
    	return 0;
    }
    
  • 相关阅读:
    模块化编程
    flex 弹性布局
    作用域与作用域链
    深入解读JavaScript面向对象编程实践
    javascript Null、Undefined 、NaN的联系与区别
    跨域常见解决方案
    Reverse Pairs
    315. Count of Smaller Numbers After Self
    2. Add Two Numbers
    657. Judge Route Circle
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11262435.html
Copyright © 2011-2022 走看看