【三校联考10.24】点亮

2024-04-11 19:18
文章标签 联考 点亮 10.24 三校

本文主要是介绍【三校联考10.24】点亮,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

@点亮@

  • @问题描述@
    • @分析1 - 随机的性质@
    • @分析2 - 利用性质@
    • @算法细节@
    • @代码@
    • @证明(过于枯燥)@
    • @END@


@问题描述@

间宫卓司种下一个小树苗,它长成了一棵 n 个点的有根树,根节点为 1,点 u 的父节点为 p u p_u pu。由于在生长过程中没有加以人工干预,所以这棵树的形态有一定的随机性:保证 p u p_u pu 是在 1 到 u − 1 中等概率随机选取的。现在,这棵树的所有节点都黯淡无光。他要使用救世主的法力来点亮一些点,使这棵树变得更加美丽。
对于有序点对 (u, v)(u≠v),如果 u 没有被点亮且以 lca(u, v) 为根的子树中没有被点亮的点数大于被点亮的点数,那么会贡献 a [ u ] [ v ] a[u][v] a[u][v] 的美丽度;如果 u 被点亮,且以 lca(u, v) 为根的子树中被点亮的点数大于等于没有被点亮的点数,则会贡献 b [ u ] [ v ] b[u][v] b[u][v] 的美丽度;否则不贡献美丽度。贡献的美丽度可以为负数。
间宫卓司想知道,通过点亮一些点,能得到整棵树的美丽度最大是多少。

输入
第一行,一个正整数 n。
第二行,n − 1 个正整数 p 2 , p 3 , . . . , p n p_2, p_3, . . . , p_n p2,p3,...,pn。保证 p u p_u pu 是在 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 ] 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] a[u][1],b[u][1],...,a[u][u1],b[u][u1],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
解释:最优方案是点亮 1 不点亮 2,此时 (1, 2) 的贡献为 69,(2, 1) 没有贡献。

样例输入2
3
1 1
-32 19 84 21
-20 0 7 -86
-37 -33 16 -66
样例输出2
39
3.4.3
解释:最优方案是不点亮 1, 2,点亮 3。

数据限制
对于 40% 的数据, 1 ≤ n ≤ 16 1 ≤ n ≤ 16 1n16
对于 80% 的数据, 1 ≤ n ≤ 200 1 ≤ n ≤ 200 1n200
对于 100% 的数据, 1 ≤ n ≤ 1000 , − 100 ≤ a [ u ] [ v ] , b [ u ] [ v ] ≤ 100 1 ≤ n ≤ 1000,−100 ≤ a[u][v], b[u][v] ≤ 100 1n1000100a[u][v],b[u][v]100,保证 p u p_u pu是在 1 1 1 u − 1 u − 1 u1 中等概率随机选取的。

@分析1 - 随机的性质@

【题解中提到:“众所周知,按此方法随机得到的树有几个常用性质:……”】
【恩我为啥什么都不知道???】

好的……既然题目中多次强调树是随机生成的,那么这一定是有用的。在这道题,随机树有以下性质可供我们使用:
1)点 i 的期望深度为 1/1 + 1/2 + 1/3+ … + 1/i ≈ ln i
2)以点 i 为根的子树期望大小 ≤ \le n/i
【其实这种树上每个节点的期望度数也是log级别的……只是这道题没有用到。】

这几个性质怎么证明呢?如果是大佬当然可以直接用数学方法推导或者用期望 dp 快速秒掉。但其实可以写一个生成随机树的程序,多刷几组验证一下,大概是那个数量级就OK。(hhhh我真是机智)

但是……emmm深度还好说,谁知道会根据子树大小来设计算法啊……

@分析2 - 利用性质@

为方便表述,如果以 i 为根的子树点亮的点多,我们称它为白点;否则为黑点。

我们对于每一个节点,计算它对答案的贡献。但是这个算法的关键点是,我们不知道它祖先的颜色,自上而下的算法不太适用。

这个时候应该将思维暴力一点:既然每个点的期望深度是log级别的,那我们不妨就设计一个以深度为底数的指数级算法来求解。深度是log级别的等价于每个点只会有log个祖先,于是就和上面的讨论有关联了:我们可以二进制枚举每个节点祖先的颜色,计算该节点的贡献,进行状压dp。

还没完。我们要判断一个子树是不是真的是白色的,不能你说它是白色的它就是白色的对吧。所以我们要将这颗子树内被点亮的点数存入状态进行转移。眼看着这个时间复杂度飙升,于是第二个性质就有用了:因为期望深度n/i,根据一些玄学的时间复杂度证明,它的时间复杂度竟然还是稳定在O(n^2)的。

具体细节请往下翻。

@算法细节@

定义 d p [ i ] [ j ] [ s ] dp[i][j][s] dp[i][j][s]表示以 i 为根的子树有 j 个被点亮的点,且从 i 到根的路径上点的黑白状态为 s 时的最大答案值。
定义 f [ 0 / 1 ] [ i ] [ s ] f[0/1][i][s] f[0/1][i][s]表示当 i 被点亮/没有被点亮,且从 i 到根的路径上点的黑白状态为 s 时 i 对答案的贡献。
定义 g [ 0 / 1 ] [ i ] [ j ] g[0/1][i][j] g[0/1][i][j]表示当 i 被点亮/没有被点亮时,所有满足lca(i, k) = (i的第 j 个祖先)的k, a [ i ] [ k ] / b [ i ] [ k ] a[i][k]/b[i][k] a[i][k]/b[i][k]之和。

g g g 数组可以靠枚举节点+计算lca在O(n^2log n)的时间内求解出来。
利用 g g g 可以在O(n*2^logn) = O(n^2)的时间内求解 f f f
转移 d p [ i ] [ j ] [ s ] dp[i][j][s] dp[i][j][s] 时可以以 j 为容量做树上背包。初始状态为 d p [ 0 / 1 ] [ i ] [ 0 / 1 ] = f [ 0 / 1 ] [ i ] [ s ] dp[0/1][i][0/1]=f[0/1][i][s] dp[0/1][i][0/1]=f[0/1][i][s]

以 i 为根时,树上背包的时间复杂度O(siz[i]2),状态有O(2dep[i])个。总时间复杂度 O ( ∑ i = 1 i ≤ n s i z [ i ] 2 ∗ 2 d e p [ i ] ) = O ( n 2 ∗ log ⁡ n ) O(\sum_{i=1}^{i\le n}siz[i]^2*2^{dep[i]})=O(n^2*\log n) O(i=1insiz[i]22dep[i])=O(n2logn)
至于为什么可以参考下面的证明。

强烈建议看一下代码的实现细节,不然可能写得很丑。

@代码@

虽然大致思路是这样的,但是还是有一些细节必须提一提:
1)dp数组如果真的那么定义,虽然时间没问题,但空间会爆炸……正确做法是将状态 s 作为一个dfs的参数传递下去。因为一个状态 s 对于它的父节点只会产生一次贡献,用过一次过后就可以直接覆盖掉了。
2)不是0/1背包或者完全背包,所以要滚动数组……
3)f数组要用vector,比着子树大小开,不然也会爆空间……
4)因为一个点作为白点和作为黑点两种情况时它们子树中含有的点亮的点的个数不一样,可以先统一将它们存入某一数组h,再进行背包。
5)记得删除不合法的状态值。
6)事实上求解深度和子树大小不需要dfs,因为它的父亲节点编号一定小于它,所以可以用递推来进行求解。
7)求lca也不需要倍增。因为每个节点的期望深度是log级别的……就直接暴力好了。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int INF = (1<<30);
const int MAXN = 1000;
struct edge{int to;edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v) {edge *p = (++ecnt);p->to = v, p->nxt = adj[u], adj[u] = p;
}
int dep[MAXN + 5], siz[MAXN + 5];
int fa[MAXN + 5], a[2][MAXN + 5][MAXN + 5];
int dp[2][MAXN + 5][MAXN + 5], g[2][MAXN + 5][30], h[MAXN + 5][MAXN + 5];
vector<int>f[2][MAXN + 5];
void Copy(int x) {for(int i=0;i<=siz[x];i++)dp[0][x][i] = dp[1][x][i];
}
void Init1(int x) {for(int i=0;i<=siz[x];i++)dp[1][x][i] = -INF;
}
void Init2(int x) {for(int i=0;i<=siz[x];i++)h[x][i] = -INF;
}
void dfs(int rt, int s) {Init1(rt); dp[1][rt][0] = f[0][rt][s];dp[1][rt][1] = f[1][rt][s];Copy(rt);int tot = 1;for(edge *p=adj[rt];p!=NULL;p=p->nxt) {Init1(rt); Init2(p->to);dfs(p->to, s<<1); dfs(p->to, s<<1|1);tot += siz[p->to];for(int i=0;i<=siz[p->to];i++)for(int j=i;j<=tot;j++)dp[1][rt][j] = max(dp[1][rt][j], dp[0][rt][j-i] + h[p->to][i]);Copy(rt);}if( s&1 ) {for(int i=(siz[rt]+1)/2;i<=siz[rt];i++)h[rt][i] = dp[0][rt][i];}else {for(int i=0;i<(siz[rt]+1)/2;i++)h[rt][i] = dp[0][rt][i];}
}
int main() {freopen("light.in", "r", stdin);freopen("light.out", "w", stdout);int n;scanf("%d", &n);for(int i=2;i<=n;i++) {scanf("%d", &fa[i]);addedge(fa[i], i);}for(int i=1;i<=n;i++) {dep[i] = dep[fa[i]] + 1;siz[i] = 1;}for(int i=n;i>=1;i--)siz[fa[i]] += siz[i];for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) {if( i == j ) continue;scanf("%d%d", &a[0][i][j], &a[1][i][j]);int p = i, q = j, r = 0;while( dep[p] > dep[q] ) p = fa[p], r++;while( dep[q] > dep[p] ) q = fa[q];while( p != q ) p = fa[p], q = fa[q], r++;g[0][i][r] += a[0][i][j];g[1][i][r] += a[1][i][j];}for(int i=1;i<=n;i++) {int t = 1<<dep[i];for(int s=0;s<t;s++) {f[0][i].push_back(0);f[1][i].push_back(0);int p = i;for(int j=0;j<dep[i];j++,p=fa[p]) {int c = ((1<<j)&s) ? 1 : 0;f[c][i][s] += g[c][i][j];}}}int ans = -INF;dfs(1, 0); dfs(1, 1);for(int i=0;i<=siz[1];i++) {ans = max(ans, h[1][i]);
//		printf("%d\n", h[1][i]);}printf("%d\n", ans);
}

@证明(过于枯燥)@

首先使用归纳法证明期望深度,记 d u d_u du为u的期望深度。边界情况 d 1 = 1 d_1=1 d1=1
假设已知 d u − 1 = 1 / 1 + 1 / 2 + . . . 1 / ( u − 2 ) + 1 d_{u-1}=1/1+1/2+...1/(u-2)+1 du1=1/1+1/2+...1/(u2)+1
则: d u = 1 + ∑ i = 1 i &lt; u d i u − 1 d_u = 1+ \dfrac{\sum_{i=1}^{i&lt;u}d_i}{u-1} du=1+u1i=1i<udi d u − 1 = 1 + ∑ i = 1 i &lt; u − 1 d i u − 2 d_{u-1} = 1+ \dfrac{\sum_{i=1}^{i&lt;u-1}d_i}{u-2} du1=1+u2i=1i<u1di
去分母: ( u − 1 ) d u = u − 1 + ∑ i = 1 i &lt; u d i (u-1)d_u=u-1+\sum_{i=1}^{i&lt;u}d_i (u1)du=u1+i=1i<udi ( u − 2 ) d u − 1 = u − 2 + ∑ i = 1 i &lt; u − 1 d i (u-2)d_{u-1}=u-2+\sum_{i=1}^{i&lt;u-1}d_i (u2)du1=u2+i=1i<u1di
两式相减: ( u − 1 ) d u − ( u − 2 ) d u − 1 = 1 + d u − 1 (u-1)d_u-(u-2)d_{u-1}=1+d_{u-1} (u1)du(u2)du1=1+du1
移项: ( u − 1 ) d u − ( u − 1 ) d u − 1 = ( u − 1 ) ( d u − d u − 1 ) = 1 (u-1)d_u-(u-1)d_{u-1}=(u-1)(d_u-d_{u-1})=1 (u1)du(u1)du1=(u1)(dudu1)=1
所以: d u − d u − 1 = 1 / ( u − 1 ) d_u-d_{u-1}=1/(u-1) dudu1=1/(u1) d u = 1 / 1 + 1 / 2 + . . . + 1 / ( u − 1 ) + 1 d_u=1/1+1/2+...+1/(u-1)+1 du=1/1+1/2+...+1/(u1)+1
得证。

一样使用归纳法证明期望子树大小,记 s u s_u su为u的期望子树大小。边界情况 s n = 1 s_n=1 sn=1
假设已知 s u + 1 = n u + 1 s_{u+1}=\dfrac{n}{u+1} su+1=u+1n
则: s u = 1 + ∑ i = u + 1 i ≤ n s i i − 1 s_u = 1+\sum_{i=u+1}^{i\le n}\dfrac{s_i}{i-1} su=1+i=u+1ini1si s u + 1 = 1 + ∑ i = u + 2 i ≤ n s i i − 1 s_{u+1} = 1+ \sum_{i=u+2}^{i\le n}\dfrac{s_i}{i-1} su+1=1+i=u+2ini1si
两式相减: s u − s u + 1 = s u + 1 u s_u-s_{u+1} = \dfrac{s_{u+1}}{u} susu+1=usu+1 s u = u + 1 u ∗ s u + 1 = n u s_u=\dfrac{u+1}{u}*s_{u+1}=\dfrac{n}{u} su=uu+1su+1=un
得证。

再来证明时间复杂度:
O ( ∑ i = 1 i ≤ n s i z [ i ] 2 ∗ 2 d e p [ i ] ) = O ( ∑ i = 1 i ≤ n ( n / i ) 2 ∗ 2 log ⁡ i ) = O ( ∑ i = 1 i ≤ n ( n / i ) 2 ∗ i ) = O ( ∑ i = 1 i ≤ n n 2 / i ) = O ( n 2 ∗ ∑ i = 1 i ≤ n 1 / i ) = O ( n 2 log ⁡ n ) O(\sum_{i=1}^{i\le n}siz[i]^2*2^{dep[i]})=O(\sum_{i=1}^{i\le n}(n/i)^2*2^{\log i})\\=O(\sum_{i=1}^{i\le n}(n/i)^2*i)=O(\sum_{i=1}^{i\le n}n^2/i)=O(n^2*\sum_{i=1}^{i\le n}1/i)\\=O(n^2\log n) O(i=1insiz[i]22dep[i])=O(i=1in(n/i)22logi)=O(i=1in(n/i)2i)=O(i=1inn2/i)=O(n2i=1in1/i)=O(n2logn)

……
我可以假装我没学过数学吗?

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。

这篇关于【三校联考10.24】点亮的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/894949

相关文章

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光 一,前言二,资源包内容三,免费获取资源包 一,前言 在创意的世界里,每一个细节都能决定一个项目的独特魅力。今天,要向大家介绍一款令人惊艳的粒子效果包 ——Super Confetti FX。 二,资源包内容 💥充满活力与动态,是 Super Confetti FX 最显著的标签。它宛如一位

没资料的屏幕怎么点亮?思路分享

这次尝试调通一个没资料的屏幕,型号是HYT13264,这个是淘宝上面的老王2.9元屏,成色很好但是长期库存没有资料和代码能点亮,仅仅只有一个引脚定义。这里我使用Arduino Nano作为控制器尝试点亮这个模块。 首先,已知别人找出来的线序如下 1 - CS2 - RST 3 - DC4 - SCK5 - SDA6 - VCC7 - GND8 - K59 - K410

RK3288 点亮LVDS屏

本文记录调试 LVDS接口屏的一些关键步骤,主要是dts文件中关于 频率、分辨率 、时序参数的设置  环境: RK3288 9tripod CV5  linux 4.4.189 LCD:JYT121XQ01 (追曦 DS1212)12.1电容触控屏   查看屏幕规格书    只要在rockchip dts 中 设置 T(HB)=Thb+Thf+Thsyn=320clock  T

STM32CubeMX 1 创建一个新工程 利用时钟点亮LED KEIL5 Jlink配置

直接上ST的官网下载STM32CubeMX安装 地址: 单片机:STM32F103C8T6 带外部8MHz晶振 目的:利用Timer和使LED按照1Hz的频率闪烁。 在此方面学霸级人物的指引下学习了,并写此文章记录,以防忘记。 新建工程 出现如下界面,中央就是这个封装的引脚图: 接下来开始配置 1. 设置外部晶振接口在PD0和PD1 单机想要配置的引脚,出现选择菜单。

最值求解 | 管理类联考数学专项

日期内容2024.9.5新建2024.9.6曦曦求最值完结 实数求最值至少至多抽屉原理工程问题线性规划一次性绝对值求最值 参考: b站跟着曦曦老师玩转【最值】

HTML和CSS网页制作成品:用代码点亮创意

HTML和CSS是网页制作的基石,它们可以用来构建各种各样的网页,从简单的个人主页到复杂的电子商务网站。本文将介绍一些有趣的HTML和CSS网页制作成品案例,并分析其背后的技术原理,激发你的创作灵感。 案例一:响应式个人简历网站         响应式个人简历网站可以根据不同的设备屏幕尺寸进行自动调整,确保在所有设备上都能清晰易读。该网站通常包含以下几个部分: 个人简介:包括姓名、工作经历

【ESP32 】VScode -window环境配置(adruino开发)(点亮LED)

创建工程 新建工程 、 进行vs code的下载,等待一段时间 工程代码 #include <Arduino.h>// put function declarations here:int myFunction(int, int);void setup() {// put your setup code here, to run once:int result = myFu

通帆科技“液氢微型发电站”:点亮氢能产业新征程

新质生产力的蓬勃发展正以磅礴之力推动产业的转型升级,氢能产业作为新质生产力的璀璨之星,成为新能源领域的关键增长极。 8 月 28 日,通帆新能源科技(山东)有限公司精心研发的 500kw “液氢微型发电站”产品成功下线交付,这一里程碑式事件标志着氢能领域的重大突破,为全国氢能产业的高质量发展注入强大动力。 在通帆科技 500kw “液氢微型发电站”产品交付使用仪式上,通帆集团董事长马国臣表示:

新基建,多杆合一点亮城市革命

前言 我国城市化发展如火如荼的进行中,在新基建的政策背景下,配合着5G应用的成熟和广泛应用,由理论转换为实际应用,就以智慧杆塔拉开了变革的序幕。智慧杆塔所展现出的“政策+标准+生态”状态,给未来更多社会资源开放树立标杆;在2020年,智慧杆塔进入规模部署阶段,智慧杆塔成为了城市发展中关键的环节。 其不但可以实现智能照明控制、节约能源,降低管理成本。还因为内有4G LTE基地台,能够处理庞大的流

【6678专题】-点亮LED灯(寄存器方式)

本章需要参考的资料为 《General Purpose Input Output (GPIO) User Guide.pdf》,具体在创龙资料文件夹目录下D:\JYTL\12DSP_FPGA\08_文档\创龙\TL6678ZH-EVM_V1.5\TL6678ZH-EVM_V1.5\6-开发参考资料\数据手册\核心板元器件\DSP\Technical Reference Manual 《Multic