zoukankan      html  css  js  c++  java
  • [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个左右吧?

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cmath>
     7 #include<cstdlib>
     8 #include<bitset>
     9 //#include<ctime>
    10 #define ll long long
    11 #define ull unsigned long long
    12 #define ui unsigned int
    13 #define d double
    14 //#define ld long double
    15 using namespace std;
    16 const int maxn=102333,modd=1000000007;const d eps=1e-7;
    17 struct zs{int too,pre;}e[maxn<<1],E[maxn];int tot,last[maxn],TOT,LAST[maxn];
    18 int sz[maxn];bool leaf[maxn],gg[maxn];
    19 d f[(1<<20)+23333];int g[(1<<20)+23333];
    20 int i,j,k,n,m;
    21 
    22 int ra;char rx;
    23 inline int read(){
    24     rx=getchar(),ra=0;
    25     while(rx<'0')rx=getchar();
    26     while(rx>='0')ra=ra*10+rx-48,rx=getchar();return ra;
    27 }
    28 
    29 
    30 void dfs(int x,int fa){
    31     int son=0;
    32     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)
    33         dfs(e[i].too,x),son++,sz[x]+=sz[e[i].too];
    34     leaf[x]=!son,sz[x]++;
    35     gg[x]=!leaf[x]&&son==1;
    36 }
    37 
    38 inline void insert(int a,int b){
    39     e[++tot].too=b,e[tot].pre=last[a],last[a]=tot,
    40     e[++tot].too=a,e[tot].pre=last[b],last[b]=tot;
    41 }
    42 inline void ins(int a,int b){
    43     E[++TOT].too=b,E[TOT].pre=LAST[a],LAST[a]=TOT;
    44 }
    45 int a[maxn],cnt;int pos[23],LEAF;int sz1[maxn],got[maxn];int num[maxn];
    46 void dfs2(int x,int _fa,int tmp){
    47     if(!gg[x]){
    48         a[++cnt]=x,num[cnt]=tmp;
    49         if(leaf[x])pos[LEAF++]=cnt;
    50         if(_fa)ins(_fa,cnt);
    51         _fa=cnt,tmp=0;
    52     }
    53     for(int i=last[x];i;i=e[i].pre)if(sz[e[i].too]<sz[x])dfs2(e[i].too,_fa,tmp+1);
    54 }
    55 int main(){
    56     n=read();
    57     for(i=1;i<n;i++)insert(read(),read());
    58     dfs(1,0),dfs2(1,0,1);
    59     
    60 //    for(i=1;i<=cnt;i++)printf("  %d",num[i]);puts("");
    61 //    for(i=0;i<LEAF;i++)printf("    %d",pos[i]);puts("");
    62     
    63     for(j=0;j<LEAF;j++)sz1[pos[j]]=1;
    64     for(j=cnt;j;j--)for(k=LAST[j];k;k=E[k].pre)sz1[j]+=sz1[E[k].too];
    65     
    66     f[0]=g[0]=1;int mx=1<<LEAF,st,tozt,tog;d tof;register int j,k;
    67     for(i=0;i<mx-1;i++){
    68         memset(got+1,0,cnt<<2);
    69         for(j=0;j<LEAF;j++)got[pos[j]]=(i&(1<<j))>0;
    70         
    71         for(j=cnt,st=1;j;st+=got[j]==sz1[j]?num[j]:0,j--)
    72             for(k=LAST[j];k;k=E[k].pre)got[j]+=got[E[k].too];
    73         tof=f[i]*st,tog=1ll*g[i]*st%modd;
    74 //        printf("zt:%d   st:%d
    ",i,st);
    75         for(j=0;j<LEAF;j++)if(!(i&(1<<j))&& f[tozt=(i|(1<<j))]<tof )f[tozt]=tof,g[tozt]=tog;
    76     }printf("%d
    ",g[mx-1]);
    77 }
    View Code
  • 相关阅读:
    数据仓库
    HiveSQL 数据定义语言(DDL)
    HiveSQL 数据操控、查询语言(DML、DQL)
    【ASP.NET Core】Blazor+MiniAPI完成文件下载
    MySQL的WAL(WriteAhead Logging)机制
    MySQL系列 | 索引数据结构大全
    眼见为实,看看MySQL中的隐藏列
    mysql的默认隔离级别:可重复读(Repeatable Read)
    缓存淘汰算法LRU算法
    Android设计模式系列(12)SDK源码之生成器模式(建造者模式)
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5956412.html
Copyright © 2011-2022 走看看