• BZOJ4455 小星星


    闲扯

    看到多个限制条件的计数题目,就想到容斥原理

    思路

    题目要求两个条件
    - 编号一一对应
    - 树上存在的边,在图上映射到的点上也应该存在
    考虑一个暴力的dp,设(dp_{i,j})表示i点编号对应到j点的方案数量
    转移显然是枚举每个子节点和每个子节点对应的编号
    对于每个子节点的不同方案数求和,不同子节点之间乘起来即可,复杂度(O(n^3))
    然后这样是错的,因为编号会有重复,不符合限制,考虑容斥
    (2^n)枚举子集表示哪几个编号不可以被对应,因为每有一个编号不可对应,就代表至少多出一对重复编号的点,就相当于至少重复0次-至少重复1次+至少重复2次...,最后就是一次都不重复的个数了,容斥一下就行了

    复杂度(O(2^n n^3))

    略微卡常,需要吸氧

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int u[100],v[100],fir[100],nxt[100],cnt,n,m;
    void addedge(int ui,int vi){
        ++cnt;
        u[cnt]=ui;
        v[cnt]=vi;
        nxt[cnt]=fir[ui];
        fir[ui]=cnt;
    }
    int mat[100][100],stack[100],topx;
    long long ans,dp[100][100];
    void dfs(int u,int fa){
        for(int i=fir[u];i;i=nxt[i]){
            if(v[i]==fa)
                continue;
            dfs(v[i],u);
        }
        for(int i=1;i<=topx;i++){
            dp[u][i]=1;
            for(int j=fir[u];j;j=nxt[j]){
                if(v[j]==fa)
                    continue;
                long long tmp=0;
                for(int k=1;k<=topx;k++)
                    if(mat[stack[i]][stack[k]])
                        tmp+=dp[v[j]][k];
                dp[u][i]*=tmp;
            }
        }
    }
    signed main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            mat[a][b]=mat[b][a]=1;        
        }
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        for(int S=0;S<(1<<n);S++){
            // printf("S=%lld ok
    ",S);
            memset(dp,0,sizeof(dp));
            topx=0;
            for(int i=1;i<=n;i++)
                if((1<<(i-1))&S)
                    stack[++topx]=i;
            dfs(1,0);
            long long tmp=0;
            for(int i=1;i<=topx;i++){
                tmp+=dp[1][i];
            }
            ans+=tmp*(((n-topx)%2)?-1:1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    BZOJ 1036 树的统计 | 树链剖分模板题
    BZOJ 3295 动态逆序对 | CDQ分治
    Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治
    BZOJ 2152 聪聪可可 | 树的点分治
    BZOJ 2458 最小三角形 | 平面分治
    51nod 1564 区间的价值 | 分治 尺取法
    Luogu 1429 平面最近点对 | 平面分治
    Codeforces 633C Spy Syndrome 2 | Trie树裸题
    一棵简单能用的左偏树
    【网络流24题】餐巾计划(图解)
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10427527.html
Copyright © 2020-2023  润新知