• bzoj4455 [Zjoi2016]小星星


    传送门

    __debug神仙计数课件的容斥入门题,有丶遭不住。

    首先根据题目可以想出一个错误的treedp的做法,设(f[u][x])表示以(u)为根的这棵子树中,以(u)为根,对应原图的(x)点的方案数,那么我们可以得到一个(O(n^3))的转移方法(枚举每个儿子以及其对应的点),但是这样需要去重,因为多个点可能在原图对应的点相同。然后考虑容斥,我们(2^n)枚举每个子集可以是哪些点被填,然后考虑每个子集会重复的部分,拿(<=n)个点的(sum_{i=1}^{n}f[1][i])减去(<=n-1)个点的加上(<=n-2)个点的...以此类推,画画韦恩图就很好理解了。

    然后这题卡常,fuck出题人

    #include<cstdio>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=20;
    ll ans,f[N][N];
    int g[N][N],t[N][N],s[N],n,m,tot;
    void dfs(int u,int fa){
        for(int i=1;i<=tot;i++)
            f[u][s[i]]=1;
        for(int i=1;i<=n;i++){
            if(!t[u][i]||i==fa)continue;
            dfs(i,u);
            for(int j=1;j<=tot;j++){
                ll sum=0;int x=s[j];
                for(int k=1;k<=tot;k++)
                    if(g[x][s[k]])sum+=f[i][s[k]];
                f[u][x]*=sum;
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),g[u][v]=g[v][u]=1;
        for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),t[u][v]=t[v][u]=1;
        for(int S=0;S<(1<<n);S++){
            tot=0;
            for(int i=0;i<n;i++)if(S&(1<<i))s[++tot]=i+1;
            dfs(1,0);
            for(int i=1;i<=tot;i++)
                ans+=((n-tot)&1?-1:1)*f[1][s[i]];
        }
        printf("%lld
    ",ans);
    }
    
    
  • 相关阅读:
    ruby之gem update --system 失败
    免费的视频资源
    java的数据类型
    函数parseQuery用于解析url查询参数
    使用闭包的方式实现一个累加函数 addNum
    正则表达式之捕获重用
    JavaScript正则表达式练习
    JavaScript的数组和字符串应用
    Sublime Text3.0的安装
    Oracle的集合运算符
  • 原文地址:https://www.cnblogs.com/yxc2003/p/10809590.html
Copyright © 2020-2023  润新知