• uoj185


    http://uoj.ac/problem/185

    首先考虑一个很假的树形 DP. dp[u][p] 表示考虑了以 u 为根的
    这个子树, 并且根映射到原图的 p . 这个显然可以 O(n3) 转移,
    是会有不同的点可能映射到同一个点. 于是考虑容斥.
    求出 dp(S) 表示映射的点集至多为 S 时的答案, 然后就可以
    O(2n*n3) 做了.

    #include<cstdio>
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    typedef long long ll;
    struct edge{
    	int to;
    	edge *nxt;
    }e[666],*las[666],*et=e;
    int map[666][666];
    ll f[666][666];
    int a[666];
    inline void add(int x,int y){
    	*++et=(edge){y,las[x]};las[x]=et;
    }
    int n,m,x,y,up;
    ll sum,ans;
    inline void dp(int now,int fa){
    	register ll tmp;
    	for(register edge *it=las[now];it;it=it->nxt)
    		if(it->to!=fa)
    			dp(it->to,now);
    	for(register int i=1;i<=a[0];++i){
    		f[now][i]=1;
    		for(register edge *it=las[now];it;it=it->nxt)
    			if(it->to!=fa){
    				tmp=0;
    				for(register int j=1;j<=a[0];++j)
    					if(map[a[i]][a[j]])
    						tmp+=f[it->to][j];
    				f[now][i]=f[now][i]*tmp;
    				if(!f[now][i])
    					break;
    			}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	FOR(i,1,m){
    		scanf("%d%d",&x,&y);
    		map[x][y]=map[y][x]=1;
    	}
    	FOR(i,2,n){
    		scanf("%d%d",&x,&y);
    		add(x,y);add(y,x);
    	}
    	up=(1<<n)-1;
    	for(register int i=1;i<=up;++i){
    		a[0]=0;
    		FOR(j,0,16)
    			if(i&(1<<j))
    				a[++a[0]]=j+1;
    		sum=0;
    		dp(1,0);
    		for(register int j=1;j<=a[0];++j)
    			sum=sum+f[1][j];
    		ans=ans+(((n^a[0])&1)?-sum:sum);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ES6中对象新增方法
    ES6中字符串新增方法
    Laya 吐槽日志.
    汇编与反汇编工具
    Mac 软件下载地址
    红米手机 android4.4.4 root之路
    查看apk安装包信息
    文件搜索
    自动发表QQ空间说说
    批量格式化json
  • 原文地址:https://www.cnblogs.com/Stump/p/8228093.html
Copyright © 2020-2023  润新知