zoukankan      html  css  js  c++  java
  • 【ZJOI2016】小星星

    题目描述

    小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有 $n$ 颗小星星,用 $m$ 条彩色的细线串了起来,每条细线连着两颗小星星。有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了 $n-1$ 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。

    小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。

    小Y想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

    输入格式

    第一行包含个 $2$ 正整数 $n,m$ ,表示原来的饰品中小星星的个数和细线的条数。

    接下来 $m$ 行,每行包含 $2$ 个正整数 $u,v$,表示原来的饰品中小星星 $u$ 和 $v$ 通过细线连了起来。这里的小星星从 $1$ 开始标号。保证 $u eq v$,且每对小星星之间最多只有一条细线相连。

    接下来行 $n-1$,每行包含个 $2$ 正整数 $u,v$,表示现在的饰品中小星星 $u$ 和 $v$ 通过细线连了起来。保证这些小星星通过细线可以串在一起。

    输出格式

    输出共 $1$ 行,包含一个整数表示可能的对应方式的数量。如果不存在可行的对应方式则输出 $0$。

    限制与约定

    各测试点满足以下约定:

    测试点 $n$ $m$ 约定
    1$=10$$leq frac {n(n-1)} {2}$
    2
    3$=17$保证新的饰品中每颗小星星与至多两颗小星星相连
    4
    5$=14$
    6
    7$=16$保证答案不超过 $10^5$
    8
    9$=17$
    10

    时间限制:$1 exttt{s}$

    空间限制:$512 exttt{MB}$


    我们对于这一类计数问题,考虑容斥来做

    这道题目其实就是对树上的结点进行重新标号,使得树上存在边的在图中也存在

    那么,我们用(f[i][j])表示树上结点(i),对于图中标号(j)的方案数

    显然(f[i][j]=prod_{}^{} (sum f[x][k])(xin C(i),(j,k)存在)),树形dp,时间复杂度(O(n^3))

    暴力枚举容斥的状态(O(2^n)),总的时间复杂度是(O(2^n*n^3)),再卡卡常数就过了

    #include<cstdio>  
    #include<iostream>  
    #include<algorithm>  
    #include<cstdlib>  
    #include<cstring>
    #include<string>
    #include<climits>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<set>
    #define LL long long
     
    using namespace std;
     
    inline char nc(){
      static char buf[100000],*p1=buf,*p2=buf;
      if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
      return *p1++;
    }
     
    inline void read(int &x){
      char c=nc();int b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
     
    inline void read(LL &x){
      char c=nc();LL b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
    
    inline int read(char *s)
    {
    	char c=nc();int len=0;
    	for(;!(c>='A' && c<='Z');c=nc()) if (c==EOF) return 0;
    	for(;(c>='A' && c<='Z');s[len++]=c,c=nc());
    	s[len++]='';
    	return len;
    }
    
    inline void read(char &x){
      for (x=nc();!(x>='A' && x<='Z');x=nc());
    }
    
    int wt,ss[19];
    inline void print(int x){
    	if (x<0) x=-x,putchar('-'); 
    	if (!x) putchar(48); else {
    	for (wt=0;x;ss[++wt]=x%10,x/=10);
    	for (;wt;putchar(ss[wt]+48),wt--);}
    }
    inline void print(LL x){
    	if (x<0) x=-x,putchar('-');
    	if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
    }
    
    int n,m,a[20][20],b[20],fa[20];
    LL ans,f[20][20],p[20];
    vector<int> c[20],d[20];
    
    void dp(int x)
    {
    	for (int i=1;i<=n;i++)
    		if (b[i]) f[x][i]=1LL;
    	for (int i=0;i<d[x].size();i++)
    		dp(d[x][i]);
    	if (x==1) return ;
    	for (int j=1;j<=n;j++)
    		p[j]=0;
    	for (int j=1;j<n;j++)
    		for (int k=j+1;k<=n;k++)
    			if (a[j][k] && b[j] && b[k]) p[j]+=f[x][k],p[k]+=f[x][j];
    	for (int j=1;j<=n;j++)
    		f[fa[x]][j]*=p[j];
    }
    
    LL calc()
    {
    	memset(f,0,sizeof(f));
    	dp(1);
    	LL res=0;
    	for (int i=1;i<=n;i++)
    		res+=f[1][i];
    	return res;
    }
    
    void work(int x)
    {
    	if (x==n+1)
    	{
    		int s=0;LL f; 
    		for (int i=1;i<=n;i++)
    			s+=b[i];
    		if (s%2==n%2) f=1LL;else f=-1LL;
    		ans+=f*calc();
    		return ;
    	}
    	for (int i=0;i<=1;i++)
    		b[x]=i,work(x+1);
    }
    
    void dfs(int x)
    {
    	for (int i=0;i<c[x].size();i++)
    		if (fa[c[x][i]]==-1)
    		{
    			fa[c[x][i]]=x;
    			d[x].push_back(c[x][i]);
    			dfs(c[x][i]);
    		}
    }
    
    int main()
    {
    	read(n);read(m);
    	int x,y;
    	for(int i=1;i<=m;i++)
    		read(x),read(y),a[x][y]=1,a[y][x]=1;
    	memset(b,0,sizeof(b));
    	for (int i=1;i<n;i++)
    		read(x),read(y),c[x].push_back(y),c[y].push_back(x);
    	memset(fa,-1,sizeof(fa));
    	fa[1]=0;
    	dfs(1);
    	ans=0;
    	work(1);
    	print(ans),puts("");
    	return 0;
    }
    
    
  • 相关阅读:
    Map 合并
    如何对hashmap按value值排序
    svn使用
    java中key-value数据有重复KEY如何存储
    linux 定时
    java 执行shell命令
    Java相对路径读取文件
    MySql之on duplicate key update详解
    前端学习资源整合
    Number浮点数运算详解
  • 原文地址:https://www.cnblogs.com/xiejiadong/p/6767160.html
Copyright © 2011-2022 走看看