码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4455: [Zjoi2016]小星星

时间:2017-12-12 21:39:24      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:for   static   online   ons   void   fread   print   php   limits   

链接

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

 

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

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

我们把1设为树的根,那么就可以得方案数$\sum\limits_{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\n",ans);
    return 0;
}

 

bzoj 4455: [Zjoi2016]小星星

标签:for   static   online   ons   void   fread   print   php   limits   

原文地址:http://www.cnblogs.com/sssy/p/8029077.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!