[51nod1673]树有几多愁
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]树有几多愁的更多相关文章
- 51nod1673 树有几多愁 - 贪心策略 + 虚树 + 状压dp
传送门 题目大意: 给一颗重新编号,叶子节点的值定义为他到根节点编号的最小值,求所有叶子节点值的乘积的最大值. 题目分析: 为什么我觉得这道题最难的是贪心啊..首先要想到 在一条链上,深度大的编号要小 ...
- 题解 [51nod1673] 树有几多愁
题面 解析 这题思路挺秒啊. 本麻瓜终于找了道好题了(还成功把ztlztl大仙拖下水了) 看到叶子节点数<=20就应该是状压啊. 然而DP要怎么写啊? 首先,考虑到编号肯定是从下往上一次增大的, ...
- 刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)
题目: lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输 ...
- 51nod 1673 树有几多愁
lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出最大烦 ...
- 51nod 1673 树有几多愁(链表维护树形DP+状压DP)
题意 lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出 ...
- 51nod 1673 树有几多愁——虚树+状压DP
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1673 建一个虚树. 一种贪心的想法是把较小的值填到叶子上,这样一个小值限制到的 ...
- 51nod算法马拉松13
A 取余最长路 不难发现路径可以拆成三条线段,只要知道两个转折点的位置就能计算出答案. 设sum(i,l,r)表示第i行从l到r元素的和,则答案可以表示为sum(1,1,x)+sum(2,x,y)+s ...
- 20160218.CCPP体系详解(0028天)
程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...
- 20160218.CCPP体系具体解释(0028天)
程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...
随机推荐
- 【python】type()、instance()
>>> a=520 >>> type(a) <class 'int'> >>> a=' >>> type(a) &l ...
- JavaScript 中 this 的详解
this 的指向 this 是 js 中定义的关键字,它自动定义于每一个函数域内,但是它的指向却让人很迷惑.在实际应用中,this 的指向大致可以分为以下四种情况. 原文作者:林鑫,作者博客:http ...
- 对Spring与SpringMVC的理解
Spring 在我的Spring --简介及环境搭建跑通Hello提到关于Spring的基本结构与功能 SpringMVC 先上一张SpringMVC的流程图 Spring MVC 是一个模型 - 视 ...
- 创建、设置和安装Windows服务
文章大部分内容转自:http://www.cnblogs.com/greatandforever/archive/2008/10/14/1310504.html:和:http://www.cnblog ...
- mac下配置caffe
Step1:安装homebrew 如果电脑上有,暂时不装.但是在step2(或者其他需要brew的情况)加完sudo之后如果仍然报错,就需要重新安装homebrew.在终端里输入如下命令: ruby ...
- bzoj 4868: [Shoi2017]期末考试
Description 有n位同学,每位同学都参加了全部的m门课程的期末考试,都在焦急的等待成绩的公布.第i位同学希望在第ti天 或之前得知所.有.课程的成绩.如果在第ti天,有至少一门课程的成绩没有 ...
- fdisk 命令详解
fdisk 作用: 查看磁盘实体使用情况,也可对硬盘分区. 选项: -b 分区大小 -l 列出指定的外围设备的分区表状况 -s 分区编号, 将指定的分区大小输出到标准输出上, 单位为区块 -u ...
- Nginx (二) Nginx的反向代理负载均衡以及日志切割
Nginx是一个高并发,高性能的服务器,可以进行反向代理以及网站的负载均衡.这些功能的运用都在配置文件中,也就是Nginx安装目录下的conf/nginx.conf. nginx.conf 1. 先来 ...
- Linux(CentOS6.5)下编译安装PHP5.6.22时报错”configure: error: ZLIB extension requires gzgets in zlib”的解决方式(确定已经编译安装Zlib,并已经指定Zlib路径)
本文地址http://comexchan.cnblogs.com/,作者Comex Chan,尊重知识产权,转载请注明出处,谢谢! 今天在CentOS6.5下编译安装PHP时,一直报错 confi ...
- 5 秒创建 k8s 集群 - 每天5分钟玩转 Docker 容器技术(115)
据说 Google 的数据中心里运行着超过 20 亿个容器,而且 Google 十年前就开始使用容器技术. 最初,Google 开发了一个叫 Borg 的系统(现在命令为 Omega)来调度如此庞大数 ...