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. OC学习15——文件I/O体系

    OC提供了丰富的I/O相关API,如果只是管理文件和目录,程序可以使用NSFileManager进行管理,包括创建.删除.移动和复制文件等:如果程序需要读取文件内容,则可通过NSFileHandle进 ...

  2. xamarin android布局

    xamarin android布局练习(1) xamarin android布局练习,基础非常重要,首先要学习的就是android的布局练习,xamarin也一样,做了几个xamarin androi ...

  3. ArcGIS API for JavaScript 4.2学习笔记[31] (补充学习)Task类

    Task这个东西很有用,是AJS中用于解决各种乱七八糟任务的一个类.它有很多子类,有用于空间分析的,有用于空间查询的,等等. 这篇作为补充学习的第一篇,也是进阶学习的第一篇,我就改个写法. 我将使用思 ...

  4. 程序员的自我救赎---11.4:FileSystem文件服务

    <前言> (一) Winner2.0 框架基础分析 (二)PLSQL报表系统 (三)SSO单点登录 (四) 短信中心与消息中心 (五)钱包系统 (六)GPU支付中心 (七)权限系统 (八) ...

  5. phpexcel导出成绩表

    效果图如下: 代码如下:代码注释不全,请大家参考phpexcel中文帮助手册 <?php require_once 'PHPExcel.php'; function bfb($n) { retu ...

  6. application19事件 20多少步骤 具体20多少只有微软知道!!!

  7. win10下部署.Net Web项目到IIS10

    本问主要介绍如何将.Net Web项目部署到IIS10下面. 1.确保iis功能已开启 开启步骤如下:控制面板->程序 点击确定,ok,iis功能已开启. 2.打开iis,绑定站点到iis下面 ...

  8. 从0到上线开发企业级电商项目_前端_01_sublime使用技巧

    一.用户设置 { "color_scheme": "Packages/Color Scheme - Default/Monokai.tmTheme", &quo ...

  9. DBA 优化法则

    硬件资源是根本,DBA是为了充分利用硬件资源:(更新中--) 统一SQL语句: 减少SQL嵌套: 执行计划返回结果集(决定计划走向): 合理使用临时表: tempdb分多文件: OLTP 条件使用变量 ...

  10. Nginx集群之基于Redis的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之基于Redis的WebApi身份验证... 1 3       Redis数据库... 2 4       Visualbox ...