51nod 1673 树有几多愁——虚树+状压DP
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1673
建一个虚树。
一种贪心的想法是把较小的值填到叶子上,这样一个小值限制到的叶子比较少。
但不太会贪心了,所以考虑 DP 。只有 20 个叶子,(不是用来暴搜的!)可以状压DP了。
dp[ S ]表示选了点集 S 的叶子的方案数。再记一个 ct[ S ] 表示选这个点集的叶子、不影响到其他叶子,最多可以填几个点。
dp[ S ]可以枚举最后一个填的是哪个叶子来转移;ct[ S ]可以在第一次枚举的时候就算出来,就是看这个 “最后一个填上的叶子” 多带来几个可以填的点。
不过这样就不知道复杂度是怎样的了。反正还是过了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define db double
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;} const int N=1e5+,K=,M=(<<)+,mod=1e9+;
int n,hd[N],xnt,to[N<<],nxt[N<<],dfn[N],tim;
int bin[K],lg[M],dep[N],pre[N][K],siz[N]; bool vis[N]; int get_lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int d=dep[x]-dep[y];
for(int t=;bin[t]<=d;t++)
if(d&bin[t])x=pre[x][t];
if(x==y)return x;
for(int t=;t>=;t--)
if(pre[x][t]!=pre[y][t])
x=pre[x][t], y=pre[y][t];
return pre[x][];
}
namespace Tr{
const int tN=;
int hd[N],xnt,to[tN],nxt[tN],fa[N];
int sta[tN],top,p[tN],tot;
int bh[N],dy[tN],vl[N],ct[M];
int dp[M]; db d2[M]; bool cmp(int u,int v){return dfn[u]<dfn[v];}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;fa[y]=x;}
void ini_dfs(int cr)
{
if(vis[cr])vl[cr]=bin[bh[cr]-];
for(int i=hd[cr],v;i;i=nxt[i])
{
ini_dfs(v=to[i]);
vl[cr]|=vl[v];
}
}
void init()
{
sort(p+,p+tot+,cmp);
sta[top=]=p[];
for(int i=;i<=tot;i++)
{
int u=p[i], lca=get_lca(u,sta[top]);
while(top&&dfn[lca]<dfn[sta[top]])
{
if(dfn[sta[top-]]<dfn[lca])
add(lca,sta[top]);
else add(sta[top-],sta[top]);
top--;
}
if(sta[top]!=lca)sta[++top]=lca;
sta[++top]=u;
}
for(int i=;i<top;i++)add(sta[i],sta[i+]);
ini_dfs(sta[]);
}
void solve()
{
init();
for(int i=,S;i<=tot;i++)
{
S=bin[i-]; dp[S]=; d2[S]=;
int cr=dy[i];//dy not bh
while(vl[fa[cr]]==S)cr=fa[cr];
ct[S]=siz[cr]+(dep[cr]-dep[fa[cr]]-);
}
for(int S=;S<bin[tot];S++)
{
if(lg[S])continue;
int T=(S&-S), cr=dy[lg[T]+], pr=cr; T=S^T;
dp[S]=(ll)dp[T]*(ct[T]+)%mod;
d2[S]=d2[T]*(ct[T]+);
while(cr&&(vl[cr]|S)==S)//token!!
cr=fa[cr];
// if(!cr) then ct[S] is wrong but has no influence
ct[S]=ct[T]+dep[pr]-dep[cr];
int tp=T;
while(tp)
{
T=(tp&-tp); tp^=T; T=S^T;
db tmp=d2[T]*(ct[T]+);
if(tmp>d2[S])
dp[S]=(ll)dp[T]*(ct[T]+)%mod,
d2[S]=d2[T]*(ct[T]+);
}
}
printf("%d\n",dp[bin[tot]-]);
}
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr,int fa)
{
dfn[cr]=++tim;
siz[cr]=; dep[cr]=dep[fa]+;
pre[cr][]=fa;
for(int t=;bin[t]<=dep[cr];t++)
pre[cr][t]=pre[pre[cr][t-]][t-];
bool flag=;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa)
{
flag=;
dfs(v,cr);siz[cr]+=siz[v];
}
if(!flag)
{
vis[cr]=; Tr::p[++Tr::tot]=cr;
Tr::bh[cr]=Tr::tot;
Tr::dy[Tr::tot]=cr;
}
}
int main()
{
n=rdn();
for(int i=,u,v;i<n;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
bin[]=;
for(int i=;i<=;i++)
bin[i]=bin[i-]<<,lg[bin[i]]=i;
dfs(,); Tr::solve();
return ;
}
51nod 1673 树有几多愁——虚树+状压DP的更多相关文章
- 刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)
题目: lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输 ...
- [51nod1673]树有几多愁
lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出最大烦 ...
- 【62测试】【状压dp】【dfs序】【线段树】
第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...
- bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...
- bzoj1402 Ticket to Ride 斯坦纳树 + 状压dp
给定\(n\)个点,\(m\)条边的带权无向图 选出一些边,使得\(4\)对点之间可达,询问权值最小为多少 \(n \leqslant 30, m \leqslant 1000\) 首先看数据范围,\ ...
- 【bzoj4006】[JLOI2015]管道连接 斯坦纳树+状压dp
题目描述 给出一张 $n$ 个点 $m$ 条边的无向图和 $p$ 个特殊点,每个特殊点有一个颜色.要求选出若干条边,使得颜色相同的特殊点在同一个连通块内.输出最小边权和. 输入 第一行包含三个整数 n ...
- BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*
BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...
- luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)
link 题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价 斯坦纳树模板题 斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e 斯坦纳 ...
- [bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp
管道连接 bzoj-4006 JLOI-2015 题目大意:给定一张$n$个节点$m$条边的带边权无向图.并且给定$p$个重要节点,每个重要节点都有一个颜色.求一个边权和最小的边集使得颜色相同的重要节 ...
随机推荐
- JavaScript学习总结(十一)——Object类详解
一.Object类介绍 Object类是所有JavaScript类的基类(父类),提供了一种创建自定义对象的简单方式,不再需要程序员定义构造函数. 二.Object类主要属性 1.constructo ...
- spring boot 学习(三)API注解记录及测试
spring boot API注解记录及测试 部分注解解析 @Controller : 修饰创建处理 http 处理对象,一般用于页面渲染时使用. @RestController : Json数据交互 ...
- FZU 2124 吃豆人 bfs
题目链接:吃豆人 比赛的时候写的bfs,纠结要不要有vis数组设置已被访问,没有的话死循环,有的话就不一定是最优解了.[此时先到的不一定就是时间最短的.]于是换dfs,WA. 赛后写了个炒鸡聪明的df ...
- cmd 环境变量设置的简单方法
1.查看当前所有可用的环境变量:输入 set 即可查看. 2.查看某个环境变量:输入 “set 变量名”即可,比如想查看temp变量的值,即输入 set temp 3.修改环境变量 :输入 “set ...
- 【转】WinForm基础
winform基础 先修基础:C#语法基础和面向对象编程 1.Winform创建解决方案 2.Winform窗体 3.MessageBOx 4.Winform登录.控制软件只运行一次.回车登录 5.W ...
- RCNN、SPP-net、Fast-RCNN和Faster-RCNN
RCNN RCNN (Regions with CNN features) 的核心思想是把图像划分成N(2000)个独立的区域,分别提取每个区域的CNN特征,然后把这些特征使用SVM等分类器进行结果预 ...
- UIImageView有关的帧动画
纯代码:设置imageView帧动画 @interface ViewController () { UIImageView *_imgView; NSMutableArray<UIImage * ...
- [LeetCode&Python] Problem 693. Binary Number with Alternating Bits
Given a positive integer, check whether it has alternating bits: namely, if two adjacent bits will a ...
- [LeetCode&Python] Problem 917. Reverse Only Letters
Given a string S, return the "reversed" string where all characters that are not a letter ...
- U盘安装电脑系统教程
[怎么使用u盘安装系统.U盘装系统.如何用U盘安装系统.U盘制作系统.U盘引导.U盘启动.U盘量产.安装系统.如何设置U盘启动] 在电脑系统的日常使用中,经常会遇到系统崩溃或重新安装系统的情况,没有光 ...