zoukankan      html  css  js  c++  java
  • bzoj 4455: [Zjoi2016]小星星

    链接

    http://www.lydsy.com/JudgeOnline/problem.php?id=4455

    dp+容斥题意大约是树上的点满足与图上的点一一对应并且图中两两有边,树中也两两有边,求满足条件的方案数

    只保证在树在图中两两有边,用dp[i][j]表示树上i点被映射到图中的j点,以i为根的子树方案数,那么方案数可以用dp在$O(n^3)$时间内处理出来

    我们把1设为树的根,那么就可以得方案数$sumlimits_{i=1}^n f(1,i) $

    这时的方案数是有重复的,考虑容斥

    答案就是ans(n)−ans(n1)+ans(n2)−ans(n3)+ans(n4).....

    我们可以二进制枚举他的子集进行容斥复杂度$O(2^n)$

    总复杂度O(2^nn^3)

    这道题就做完了

    #include<cstdio>
    #include<cstring>
    
    const int maxn = 50;
    const int MAXN=1e6+10;
    inline char nc()
    {
        static char buf[MAXN],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        char c=nc();int x=0;
        while(c<'0'||c>'9')c=nc();
        while(c>='0'&&c<='9')x=x*10+c-'0',c=nc();
        return x;
    }
    
    struct node{
        int v,next;
    }edge[maxn*4];
    int n,m,num;
    int map[maxn*maxn][maxn*maxn],head[maxn];
    inline void add_edge(int u,int v) {
        edge[++num].v=v;edge[num].next=head[u];head[u]=num;
    }
    int node_num=0;
    int node[maxn];long long dp[maxn][maxn];
    void dfs(int x,int fa) {
        for(int i=1;i<=n;++i)dp[x][node[i]]=1;
        for(int i=head[x];i;i=edge[i].next) {
            int v=edge[i].v;
            if(v==fa)continue;
            dfs(v,x);
            for(int j=1;j<=node_num;++j) {
                long long cnt=0;
                for(int k=1;k<=node_num;++k) 
                    if(map[node[j]][node[k]])
                        cnt+=dp[v][node[k]];
                dp[x][node[j]]*=cnt;
            }
    
        }
        
    }
    int main() {
        n=read(),m=read();
        long long ans=0;
        for(int a,b,i=1;i<=m;++i) {
            a=read(),b=read();
            map[a][b]=map[b][a]=1;
        }
        for(int a,b,i=1;i<n;++i) {
            a=read(),b=read();
            add_edge(a,b);
            add_edge(b,a);
        }
        for(int i=1;i<(1<<n);++i) {
            node_num=0;
            for(int j=1;j<=n;++j) {
                if((1<<j-1)&i)node[++node_num]=j;
            }
            dfs(1,1);
            long long tot=0;
            for(int j=1;j<=node_num;++j) 
                tot+=dp[1][node[j]];
            if((node_num&1)==(n&1))ans+=tot;
            else ans-=tot;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    sqlserver中递归写法
    keytools命令生成证书
    java中sql语句快速处理
    select * 替换写法
    oracle行转列
    oracle中查看当前用户的表结构、主键、索引
    Servlet三种实现方式
    【python之旅】python的面向对象
    【python之旅】python的模块
    【python之旅】python的基础三
  • 原文地址:https://www.cnblogs.com/sssy/p/8029077.html
Copyright © 2011-2022 走看看