• [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
  • 相关阅读:
    Groovy新手教程
    cocos2d-x v3.2 FlappyBird 各个类对象详细代码分析(6)
    开机黑屏 仅仅显示鼠标 电脑黑屏 仅仅有鼠标 移动 [已成功解决]
    病毒木马查杀第002篇:熊猫烧香之手动查杀
    Activity具体解释(生命周期、以各种方式启动Activity、状态保存,全然退出等)
    白话经典算法系列之六 高速排序 高速搞定
    UVA580-Critical Mass
    FPGA 时序问题
    SVD神秘值分解
    Java中Integer类的方法
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5956412.html
Copyright © 2020-2023  润新知