题目传送门(内部题121)


输入格式

  第一行,一个正整数$n$。
  第二行,$n-1$个正整数$p_2,p_3,...,p_n$。保证$p_u$是在$1$到$u-1$中等概率随机选取的。
  接下来$n$行,第$u$行有$2(n-1)$个数,分别为$a[u][1],b[u][1],...,a[u][u−1],b[u][u-1],a[u][u+1],b[u][u+1],...,a[u][n],b[u][n]$(即去掉$v=u$后的$n-1$对)。
  读入量较大,建议使用读入优化。


输出格式

  一个整数表示能得到整棵树的美丽度的最大值。


样例

样例输入1:

2
1
-71 69
100 -47

样例输出1:

69

样例输入2:

3
1 1
-32 19 84 21
-20 0 7 -86
-37 -33 16 -66

样例输出2:

39


数据范围与提示

样例$1$解释:

  最优方案是点亮$1$不点亮$2$,此时$(1,2)$的贡献为$69$,$(2,1)$没有贡献。

样例$2$解释:

  最优方案是不点亮$1,2$,点亮$3$。

数据范围:

  对于$40\%$的数据,$1\leqslant n\leqslant 16$。
  对于$80\%$的数据,$1\leqslant n\leqslant 200$。
  对于$100\%$的数据,$1\leqslant n\leqslant 1,000,-100\leqslant a[u][v],b[u][v]\leqslant 100$,保证$p_u$是在$1$到$u-1$中等概率随机选取的。


题解

题目中不断强调数据随机,那么我们先挖掘一下其性质:

  $\alpha.$点$u$的期望深度为:$\mathbb{E}d_u=H_{u-1}$(其中调和级数$H=\sum \limits_{i=1}^n\frac{1}{i}=\ln n+\Theta(1)$);其实,你可以简单的将其理解为$u$的期望深度为$1+\ln_{u-1}$。

  $\beta.$点$u$的期望子树大小$\mathbb{E}z_u\leqslant \frac{n}{u}$。

  $\gamma.$树上每个节点的度数是$\log$级别的,这条性质对这道题没有帮助,自动忽略即可。

有了这些性质,考虑如何利用这些性质。

因为期望深度很小,也就是祖先很少,于是我们可以考虑用状压的方式记录其祖先的状态。

判断一棵子树内被点亮的点多还是没有被点亮的点多时需要将被点亮的点的状态存入其中进行转移,但是因为子树的期望大小,所以时间复杂度还是$\Theta(n^2)$级别的。

利用了这些性质,思考进一步解题。

既然已经说了用状压,那八成就是$DP$了,先作出如下定义$\downarrow$

  $\alpha.$设$dp[i][j][s]$表示以$i$为根的子树内有$j$个点被点亮,且从$i$到跟的路径上的点亮状态为$s$的最大贡献。

  $\beta.$设$f[0/1][i][s]$表示当$i$有没有被点亮的情况下从$i$到跟的路径上的点亮状态为$s$的最大贡献。

  $\gamma.$设$g[0/1][i][j]$表示当$i$有没有被点亮的情况下所有与$i$的$lca$为$j$的点的$a$或$b$数组的和。

$g$数组可以在$\Theta(n^2)$(均摊)的时间内暴力求出,注意这里没有必要使用倍增求$lca$。

利用$g$数组可以在$\Theta(n^2)$(均摊)的时间内求出$f$,然后做一个树上背包即可得到$dp$数组,初始$dp[0/1][i][0/1]=f[0/1][i][s]$。

$f$数组有空间问题,可以用$unordered\text{_}map$存储。

最后做三个证明。

$\mathcal{A}.$时间复杂度证明:

$$\begin{array}{ll}\Theta\left(\sum\limits_{u=1}^n2^{\mathbb{E}d_u}(\mathbb{E}z_u)^2\right) &=& \Theta\left(\sum\limits_{u=1}^n2^{\ln u}\left(\frac{n}{u}\right)^2\right) \\ &=& \Theta\left(\sum\limits_{u=1}^nu^{\ln 2}\left(\frac{n}{u}\right)^2\right) \\ &=& \Theta\left(\sum\limits_{u=1}^n\frac{n^2}{u^{2-\ln 2}}\right) \\ &\leqslant& \Theta\left(n^2\sum\limits_{u\geqslant 1}\frac{1}{u^{2-\ln 2}}\right) \\ &=& \Theta(n^2\zeta(2-\ln 2)) \\ &=& \Theta(n^2)\end{array}$$

但是实际上$\mathbb{E}(2^{d_u})\geqslant 2^{\mathbb{E}d_u}$,$\mathbb{E}(z_u^2)\geqslant (\mathbb{E}z_u)^2$,所以实际上时间复杂度大约是$\Theta(\frac{n^2\ln^2n}{\ln\ln n})$的。

$\mathcal{B}.$点$u$的期望深度$d_u$的证明:

边界$d_1=1$,那么:

$$d_u=1+\dfrac{\sum\limits_{v=1}^{u-1}d_v}{u-1}$$

再记:

$$D_u=\sum\limits_{v=1}^ud_v$$

带入上式,得:

$$D_u-D_{u-1}=1+\frac{D_{u-1}}{u-1}$$

整理,得:

$$\frac{D_u}{u}=\frac{1}{u}+\frac{D_{u-1}}{u-1}\Rightarrow\frac{D_u}{u}=H_u$$

所以:

$$d_u=1+\frac{D_{u-1}}{u-1}=1+H_{u-1}=\ln u+\Theta(1)$$

$\mathcal{C}.$点$u$的期望子树大小$z_u$的证明:

边界$z_n=1$,那么可以估算为:

$$z_u=1+\sum\limits_{v=u+1}^n\frac{z_v}{v-1}$$

再记:

$$Z_u=\sum\limits_{v=u}^n\frac{z_u}{v-1}$$

则:

$$z_u=(u-1)(Z_u-Z_{u+1})$$

带入原式,得:

$$(u-1)(Z_u-Z_{u+1})=1+Z_{u+1}$$

整理,得:

$$(u-1)Z_u=1+uZ_{u+1}\Rightarrow(u-1)Z_u=n-u+1$$

即:

$$Z_u=\frac{n-u+1}{u-1}$$

所以:

$$z_u=1+Z_{u+1}=\frac{n}{u}$$

时间复杂度:$\Theta(\frac{n^2\ln^2n}{\ln\ln n})$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[1001];
int head[1001],cnt;
int n;
int fa[1001];
int a[1001][1001],b[1001][1001],size[1001],depth[1001];
int dp[2][1001][1001],g[2][1001][20],h[1001][1001];
bool now[1001];
unordered_map<int,int> f[2][1001];
int ans=-0x3f3f3f3f;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
depth[e[i].to]=depth[x]+1;
dfs(e[i].to);
size[x]+=size[e[i].to];
}
}
int LCA(int x,int y)
{
int res=0;
while(depth[y]<depth[x]){x=fa[x];res++;}
while(depth[x]<depth[y])y=fa[y];
while(x!=y){x=fa[x];y=fa[y];res++;}
return res;
}
void dfs(int x,int s)
{
now[x]^=1;
memset(dp[now[x]][x],-0x3f,sizeof(dp[now[x]][x]));
dp[now[x]][x][0]=f[0][x][s];
dp[now[x]][x][1]=f[1][x][s];
int sz=1;
for(int i=head[x];i;i=e[i].nxt)
{
now[x]^=1;
memset(dp[now[x]][x],-0x3f,sizeof(dp[now[x]][x]));
memset(h[e[i].to],-0x3f,sizeof(h[e[i].to]));
dfs(e[i].to,s<<1);
dfs(e[i].to,s<<1|1);
sz+=size[e[i].to];
for(int j=0;j<=size[e[i].to];j++)
for(int k=j;k<=sz;k++)
dp[now[x]][x][k]=max(dp[now[x]][x][k],dp[!now[x]][x][k-j]+h[e[i].to][j]);
}
if(s&1)for(int i=((size[x]+1)>>1);i<=size[x];i++)h[x][i]=dp[now[x]][x][i];
else for(int i=0;i<=((size[x]+1)>>1);i++)h[x][i]=dp[now[x]][x][i];
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{scanf("%d",&fa[i]);add(fa[i],i);}
depth[1]=1;dfs(1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)continue;
scanf("%d%d",&a[i][j],&b[i][j]);
int dep=LCA(i,j);
g[0][i][dep]+=a[i][j];
g[1][i][dep]+=b[i][j];
}
for(int i=1;i<=n;i++)
{
int state=1<<depth[i];
for(int s=0;s<(1<<depth[i]);s++)
for(int j=0;j<depth[i];j++)
if((1<<j)&s)f[1][i][s]+=g[1][i][j];
else f[0][i][s]+=g[0][i][j];
}
dfs(1,0);dfs(1,1);
for(int i=0;i<=n;i++)ans=max(ans,h[1][i]);
printf("%d",ans);
return 0;
}

rp++

[CSP-S模拟测试]:点亮(状压DP+树上背包DP)的更多相关文章

  1. [CSP-S模拟测试]:装饰(状压DP)

    题目传送门(内部题114) 输入格式 第一行一个正整数$n$. 接下来一行$n-1$个正整数,第$i$个数为$f_{i+1}$. 接下来一行$n$个数,若第$i$个数为$0$则表示林先森希望$i$号点 ...

  2. [CSP-S模拟测试]:巨神兵(状压DP)

    题目描述 欧贝利斯克的巨神兵很喜欢有向图,有一天他找到了一张$n$个点$m$条边的有向图.欧贝利斯克认为一个没有环的有向图是优美的,请问这张图有多少个子图(即选定一个边集)是优美的?答案对$1,000 ...

  3. 树形DP和状压DP和背包DP

    树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...

  4. 6.28 NOI模拟赛 好题 状压dp 随机化

    算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...

  5. 【62测试】【状压dp】【dfs序】【线段树】

    第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...

  6. 2018.10.05 NOIP模拟 上升序列(状压dp)

    传送门 状压dp好题. 首先需要回忆O(nlogn)O(nlog n)O(nlogn)求lislislis的方法,我们会维护一个单调递增的ddd数组. 可以设计状态f(s1,s2)f(s1,s2)f( ...

  7. 2018.10.01 NOIP模拟 偷书(状压dp)

    传送门 状压dp经典题. 令f[i][j]f[i][j]f[i][j]表示到第i个,第i−k+1i-k+1i−k+1~iii个物品的状态是j时的最大总和. 然后简单维护一下转移就行了. 由于想皮一下果 ...

  8. 【10.26校内测试】【状压?DP】【最小生成树?搜索?】

    Solution 据说正解DP30行??? 然后写了100行的状压DP?? 疯狂特判,一算极限时间复杂度过不了aaa!! 然而还是过了....QAQ 所以我定的状态是待转移的位置的前三位,用6位二进制 ...

  9. [noip模拟]食物中毒<暴搜+状压优化>

    问题描述 Bqc经过一段时间的研究发现,要解这种毒需要一种特殊的药物.不幸的是,这种药物在 市面上不存在,没有办法Bqc只好亲自制得这种药物.它含有M种化学物质A1,A2,…,AM.现 在Bqc的手上 ...

随机推荐

  1. 版本控制器之SVN(二)

    安装重启以后,在菜单栏找到TortoiseSVN程序 启动以后 点击: 填写相应的信息: 可以看到项目的相关信息 选中仓库,右键 > Browse Repository 进入如下界面: 可以打开 ...

  2. 前端-CSS-初探-注释-语法结构-引入方式-选择器-选择器优先级-01(待完善)

    目录 CSS(Cascading Style Sheet) CSS注释 CSS语法结构 CSS的三种引入方式 选择器 伪类.伪元素选择器速查 CSS选择器优先级***** 选择器相同的情况下 选择器不 ...

  3. Lock Puzzle CodeForces - 936C (构造)

    大意: 给定字符串$s$,$t$, 每次操作可以将$S=AB$变为$S=B^RA$, 要求$3n$次操作内将$s$变为$t$. #include <iostream> #include & ...

  4. java 给定一个日期期间 返回形如Mar 2015 3/20-3/31的数据

    最近一个项目中有个前台对于表头要求: 给定一个日期期间返回形如 Mar 2015 3/20-3/31Apr 2015 4/1-4/30 这样的月年数据,简单的写了下代码,暂时没想到更好的办法 例如传进 ...

  5. mysql设计与优化以及数据库表设计与表开发规范

    一.设计问题? 1.主键是用自增还是UUID ? Innodb 中的主键是聚簇索引. 如果主键是自增的,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的 ...

  6. 应对Hadoop集群数据疯长,这里祭出了4个治理对策!

    一.背景 在目前规模比较大的互联网公司中,总数据量能达到10PB甚至几十PB数据量的公司,我认为中国已经有超过了20家了.而在这些公司中,也有很多家公司的 日数据增长达到100TB+ 了. 所以我们每 ...

  7. ajax的交互原理,同步和异步的区别

    ajax的交互原理分别为: 创建对象——建立连接——发送数据——注册回调——执行回调 var xhr=new XMLHttpRequest()//创建对象 xhr.open(请求,url,true或者 ...

  8. 详解Wox

    Wox 是一款国产开源免费的软件快捷启动工具,它可以快速搜索并打开你电脑上的程序.文件.或是查词翻译.网站查找等其他操作,同时还支持插件安装. Tips: 如果你需要用到文件的快速搜索.打开功能,需要 ...

  9. Linux搭建局域网yum源和后期在yum源中更新rpm包方法

    在内网中搭建自己的yum源,可以方便在内网中使用,下面简单介绍搭建局域网yum源的方法和后期更新yum源rpm包的方法. 一.搭建局域网yum源 1.需要在局域网访问,首先需要一个web服务器,比如a ...

  10. 自动化运维——MySQL备份脚本(二)

    使用if语句编写MySQL备份脚本 代码: #!/bin/bash #auro backup mysql db #by steve yu #define backup path BAK_DIR=/da ...