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. iOS MJRefresh下拉、上拉刷新自定义以及系统详细讲解

    更新: MJRefresh 更新功能,默认根据数据来源 自动显示 隐藏footer,这个功能可以关闭 DoctorTableView.mj_footer.automaticallyHidden = N ...

  2. 2018年的UX设计师薪酬预测,你能拿多少?

    以下内容由Mockplus团队翻译整理,仅供学习交流,Mockplus是更快更简单的原型设计工具.   一个经验丰富的设计师完全可以根据地区和专业来可以预期薪酬之间的差距,其中悬殊最高可达80K. 本 ...

  3. Windows as a Service(4)——使用Intune管理Windows10更新

    这是这个系列的最后一篇文章,我已经花了三篇的篇幅和大家分享有关于Windows as a Serivce的相关内容,链接如下: Windows as a Service(1)-- Windows 10 ...

  4. 关于js代码执行顺序

    上网查了一下关于这个方面的资料,大部分都是关于两个script标签中的js代码和变量以及函数提升方面的知识. 1.两个script标签 <script> alert("我是代码块 ...

  5. userdel 命令详解

    userdel  作用: 删除指定用户,以及用户相关的文件. 如不加选项,则仅删除用户账号,而不删除相关文件 选项: -f:强制删除用户,即时用户当前已登录 -r:删除用户的同时删除与用户相关的所有文 ...

  6. MySQL小抄

    以下是MySQL5.7中的一些tips&tricks(持续更新中): Use of an unqualified * with other items in the select list m ...

  7. js拖拽的封装

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  8. HY.Mail:C#简单、易用的邮件工具库

    一.开发HY.Mail的初衷 Nuget或者github上有很多成熟且优秀的邮件库可以使用, 但是目前找到的使用都不够简洁或者不适合我的使用场景 我的场景是开发应用场景(例如系统通知.运维通知),而非 ...

  9. web打印总结

    一.打印样式 区别显示和打印的样式 使用media="print"控制打印时的样式,如下: 打印时不显示打印按钮,设置页面宽度 <style media="prin ...

  10. (五):C++分布式实时应用框架——微服务架构的演进

    C++分布式实时应用框架--微服务架构的演进 上一篇:(四):C++分布式实时应用框架--状态中心模块 版权声明:本文版权及所用技术归属smartguys团队所有,对于抄袭,非经同意转载等行为保留法律 ...