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

  update:数据保证叶子节点个数<=20。

 Input
  第一行一个数n(1<=n<=100000)。
  接下来n-1行,每行两个数ai,bi(1<=ai,bi<=n),表示存在一条边连接这两个点。
Output
  一行表示答案

  显然小的编号应该丢给深度大的点,也就是说,从小到大确定编号的话,一个点子树内的所有其他点都被确定了之后 这个点才会(并且一定要)被确定。

  但具体叶子之间谁先谁后还是有影响的。。。

  就直接状压一波,f[i]表示已经确定编号的叶子的状态为i时的最大烦恼值(叶子只要给了编号,对烦恼值的贡献就确定下来了)。

  先把原树上一些没用的点删掉,只保留叶子和有多个儿子的节点(其实就是虚树...)

  每次枚举一个状态的时候,直接在虚树上暴力求出到底哪些点的编号已被确定了。这样就知道下一个叶子的编号是什么...再枚举下一个确定的是哪个叶子并转移就好了。

  因为答案很大,比较方案优劣的时候可以用double。。

  时间复杂度O(2^n*虚树节点数),虚树节点数大概就40个左右吧?

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<bitset>
//#include<ctime>
#define ll long long
#define ull unsigned long long
#define ui unsigned int
#define d double
//#define ld long double
using namespace std;
const int maxn=,modd=;const d eps=1e-;
struct zs{int too,pre;}e[maxn<<],E[maxn];int tot,last[maxn],TOT,LAST[maxn];
int sz[maxn];bool leaf[maxn],gg[maxn];
d f[(<<)+];int g[(<<)+];
int i,j,k,n,m; int ra;char rx;
inline int read(){
rx=getchar(),ra=;
while(rx<'')rx=getchar();
while(rx>='')ra=ra*+rx-,rx=getchar();return ra;
} void dfs(int x,int fa){
int son=;
for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)
dfs(e[i].too,x),son++,sz[x]+=sz[e[i].too];
leaf[x]=!son,sz[x]++;
gg[x]=!leaf[x]&&son==;
} inline void insert(int a,int b){
e[++tot].too=b,e[tot].pre=last[a],last[a]=tot,
e[++tot].too=a,e[tot].pre=last[b],last[b]=tot;
}
inline void ins(int a,int b){
E[++TOT].too=b,E[TOT].pre=LAST[a],LAST[a]=TOT;
}
int a[maxn],cnt;int pos[],LEAF;int sz1[maxn],got[maxn];int num[maxn];
void dfs2(int x,int _fa,int tmp){
if(!gg[x]){
a[++cnt]=x,num[cnt]=tmp;
if(leaf[x])pos[LEAF++]=cnt;
if(_fa)ins(_fa,cnt);
_fa=cnt,tmp=;
}
for(int i=last[x];i;i=e[i].pre)if(sz[e[i].too]<sz[x])dfs2(e[i].too,_fa,tmp+);
}
int main(){
n=read();
for(i=;i<n;i++)insert(read(),read());
dfs(,),dfs2(,,); // for(i=1;i<=cnt;i++)printf(" %d",num[i]);puts("");
// for(i=0;i<LEAF;i++)printf(" %d",pos[i]);puts(""); for(j=;j<LEAF;j++)sz1[pos[j]]=;
for(j=cnt;j;j--)for(k=LAST[j];k;k=E[k].pre)sz1[j]+=sz1[E[k].too]; f[]=g[]=;int mx=<<LEAF,st,tozt,tog;d tof;register int j,k;
for(i=;i<mx-;i++){
memset(got+,,cnt<<);
for(j=;j<LEAF;j++)got[pos[j]]=(i&(<<j))>; for(j=cnt,st=;j;st+=got[j]==sz1[j]?num[j]:,j--)
for(k=LAST[j];k;k=E[k].pre)got[j]+=got[E[k].too];
tof=f[i]*st,tog=1ll*g[i]*st%modd;
// printf("zt:%d st:%d\n",i,st);
for(j=;j<LEAF;j++)if(!(i&(<<j))&& f[tozt=(i|(<<j))]<tof )f[tozt]=tof,g[tozt]=tog;
}printf("%d\n",g[mx-]);
}

[51nod1673]树有几多愁的更多相关文章

  1. 51nod1673 树有几多愁 - 贪心策略 + 虚树 + 状压dp

    传送门 题目大意: 给一颗重新编号,叶子节点的值定义为他到根节点编号的最小值,求所有叶子节点值的乘积的最大值. 题目分析: 为什么我觉得这道题最难的是贪心啊..首先要想到 在一条链上,深度大的编号要小 ...

  2. 题解 [51nod1673] 树有几多愁

    题面 解析 这题思路挺秒啊. 本麻瓜终于找了道好题了(还成功把ztlztl大仙拖下水了) 看到叶子节点数<=20就应该是状压啊. 然而DP要怎么写啊? 首先,考虑到编号肯定是从下往上一次增大的, ...

  3. 刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)

    题目: lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输 ...

  4. 51nod 1673 树有几多愁

    lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出最大烦 ...

  5. 51nod 1673 树有几多愁(链表维护树形DP+状压DP)

    题意 lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出 ...

  6. 51nod 1673 树有几多愁——虚树+状压DP

    题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1673 建一个虚树. 一种贪心的想法是把较小的值填到叶子上,这样一个小值限制到的 ...

  7. 51nod算法马拉松13

    A 取余最长路 不难发现路径可以拆成三条线段,只要知道两个转折点的位置就能计算出答案. 设sum(i,l,r)表示第i行从l到r元素的和,则答案可以表示为sum(1,1,x)+sum(2,x,y)+s ...

  8. 20160218.CCPP体系详解(0028天)

    程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...

  9. 20160218.CCPP体系具体解释(0028天)

    程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...

随机推荐

  1. TCP/IP----基本知识

    就以这篇文章为起点,开始自己的学习计算机网络之路.这些仅是我个人之言,如有差错,希望读者能够逐一指出,在下不胜感激. 首先,我们需要知道一些关于网络的基本知识. 网络中的关系大多为拓扑结构.那么,何为 ...

  2. [array] leetcode - 40. Combination Sum II - Medium

    leetcode - 40. Combination Sum II - Medium descrition Given a collection of candidate numbers (C) an ...

  3. Button的五种点击事件

    1.内部类方式 class MyOnClickListener implements View.OnClickListener{ /** * Called when a view has been c ...

  4. Java 集成 速卖通开发.

    一.申请成为开发者 申请入口:http://isvhz.aliexpress.com/isv/index.htm 说明文档:http://activities.aliexpress.com/open/ ...

  5. 搭建基于Linux6.3+Nginx1.2+PHP5+MySQL5.5的Web服务器全过程----转载

    之前的Web服务器都是通过yum搭建的,想要添加新模块或者更新某些软件都很不方便(牵一发而动全身啊!).所以,现在准备将环境改为源码编译安装,这样便于调整,性能上也会比yum方式好很多.以下是我的安装 ...

  6. HTML5学习知识点

    一.文档问题 1.html5新标签:section.header.footer.nav.aside.blockquote.q.fieldest.figure.address.article.detai ...

  7. c#访问oracle数据库

    想在c#中访问oracle数据库,毕竟是开发,想要轻量级访问oracle,客户机上无需安装oracle环境就能正常运行程序. 在网上找了相关资料,只需要引用一个dll即可实现. 访问代码(需引用dll ...

  8. for 在项目实战中用的比较多

    for循环编程语言中的语句之一,用于循环执行.for循环是开界的,它的一般形式为: for(; <条件表达式>; ) 语句: 初始化通常是一个赋值语句, 它用来给循环控制变量赋初值: 条件 ...

  9. java 实现的c当中的几道题

    package javastudy; /* * 利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示, 60分以下的用C表示. */ import jav ...

  10. 关于vs2010下水晶报表的使用入门

    关于vs2010下使用水晶报表了解情况记录如下: 1.首先vs2010不再自带水晶报表控件了,需要下载安装vs2010配套的水晶报表控件:CRforVS_13_0.这个控件安装很简单,基本上都选择默认 ...