zoukankan      html  css  js  c++  java
  • 51nod 1673 树有几多愁

    Description

    lyk有一棵树,它想给这棵树重标号。
    重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号。
    这棵树的烦恼值为所有叶子节点的值的乘积。
    lyk想让这棵树的烦恼值最大,你只需输出最大烦恼值对1e9+7取模后的值就可以了。
    注意一开始1号节点为根,重标号后这个节点仍然为根。
    数据保证叶子节点个数<=20,N<=100000

    Solution

    容易想到深度越大的节点编号要尽量小,且从叶子到根节点经过的节点的编号是递增的
    因为我们要让叶子节点编号尽量的大,所以能往上多编号就多编号
    注意到一个节点子树内的点的编号如果都确定了,为了符合上述贪心策略,就可以直接确定这个点的编号了,为(size+1)
    然后发现儿子数为 (1)的节点是没有用的,因为可以直接一路确定上去,只用知道这样的点的个数即可
    把这些点去掉之后,由于叶子节点数只有(20),所以去掉之后,剩下的点不超过 (39) 个了,于是可以暴力做了
    把叶子节点状压 , 设 (f[i]) 表示状态为 (i) 的节点烦恼值的最大值
    让能确定编号的点都确定好,得到下一个节点的编号,枚举把这个编号给哪个叶子即可

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10,mod=1e9+7;
    int head[N],nxt[N<<2],to[N<<2],num=0,n,in[N],sz[N],v[N],leaf[N];
    int Head[N],b[N],cnt=0,sum=0,w[N],g[1<<20];double f[1<<20];
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void Link(int x,int y){nxt[++num]=Head[x];to[num]=y;Head[x]=num;}
    inline void dfs(int x,int last,int fa){
    	sum++;
    	if(in[x]!=2){
    		b[++cnt]=x;w[cnt]=sum;sum=0;
    		if(fa!=x)Link(fa,x),fa=x;
    	}
    	for(int i=head[x];i;i=nxt[i])if(to[i]!=last)dfs(to[i],x,fa);
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      int x,y,m=0,tot;
      scanf("%d",&n);
      for(int i=1;i<n;i++){
    	  scanf("%d%d",&x,&y);
    	  link(x,y);link(y,x);
    	  in[x]++;in[y]++;
      }
      in[1]=-1;dfs(1,1,1);
      for(int i=2;i<=n;i++)if(in[i]==1)leaf[++m]=i,sz[i]=1;
      for(int i=cnt;i>=1;i--)
    	  for(int j=Head[b[i]];j;j=nxt[j])
    		  sz[b[i]]+=sz[to[j]];
      tot=(1<<m)-1;
      f[0]=g[0]=1;
      for(int i=0;i<tot;i++){
    	  for(int j=1;j<=cnt;j++)v[b[j]]=0;
    	  for(int j=1;j<=m;j++)
    		  if(i&(1<<(j-1)))v[leaf[j]]=1;
    	  int id=1;
    	  for(int j=cnt;j>=1;j--){
    		  for(int k=Head[b[j]];k;k=nxt[k])
    			  v[b[j]]+=v[to[k]];
    		  if(v[b[j]]==sz[b[j]])id+=w[j];
    	  }
    	  double t=f[i]*id;
    	  for(int j=1;j<=m;j++)
    		  if(!(i&(1<<(j-1))) && t>f[1<<(j-1)|i])
    			  f[1<<(j-1)|i]=t,g[1<<(j-1)|i]=1ll*id*g[i]%mod;
      }
      cout<<g[tot]<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    noip2012 同余方程
    bzoj1477 poj1061 青蛙的约会
    Nginx 从入门到放弃(五)
    Nginx 从入门到放弃(四)
    Nginx 从入门到放弃(三)
    Nginx 从入门到放弃(二)
    Nginx 从入门到放弃(一)
    python三大神器之fabric
    Docker 学习(一)
    linux就该这么学 第一天学习笔记
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8460118.html
Copyright © 2011-2022 走看看