2020正睿暑期班DAY1小结

树形DP

【树上最大独立集】

解释:对于图G=(V,E),从V中选尽量多的点为一个集合,使这些点之间没有边相连

方法一  暴搜  枚举每个点选与不选  O(2n

 

方法二  贪心 

从叶子节点开始,以根为结束,能选的点尽量选

 刚开始听这个算法的时候还以为是一个反面教材,直到给出了证明(类似反证吧)

我们设当前点为点U,且点U这时候可以选(即它的儿子都没有被选过)

1.如果点U在最优方案之中,不做考虑

2.如果点U没有在最优方案之中——

2020正睿暑期班DAY1小结_第1张图片

 

 如果点U不选,那么按照逻辑,v是选了的

那我们这时候选U,V受到影响不能再选

看似我们改变了整盘棋局,但实际上只是一个棋子的交换,我们只是把u和v的状态交换了一下,那么会不会有影响呢?

- 对于点U,它的子树的状态是已经定了的,即都没有选,那么U的状态变化显然与子树没有关系了

- 对于点V,它从选转为不选,那么接下来的影响显然是可以让V的更多子树的状态变为选(因为不受父亲的影响了,选与不选状态自由),而对于点V的父亲,显然也是状态自由了~

所以综合U V,并且每个点的贡献值均为1的情况来看,U的“选”只会让最终方案“不更劣”

In short 能选则选的方案是成立的

代码思路:

dfs处理一遍,存下深搜顺序

按深搜倒序开始跑(为了先从叶子开始),如果这个点没有被标记,那么就选它,并且标记它的父亲

但是,这种方法是建立在父亲和儿子价值等价的情况下,所以如果点权不同,是不能使用贪心的

方法三  DP

当题目变化为  树上最大独立集的时候,无法在子树内直接作出决策

存在不确定性——解决不确定性——枚举不确定性

(回到最初的起点~)

事实上,和子树有出现关系冲突的只有根节点,所以只要考虑根节点选与不选的最大值就可以了

例题:没有上司的舞会

dp[x][0/1]  根节点为x的子树的最大值,0/1表示x的选与不选

1.dp[x][0]=max(dp[son][0],dp[son][1])

2.dp[x][1]=dp[son][0]

 

【树的重心】

解释:对于一个树,把这个点删去后,其余的连通块的最大节点数最小

我们先解决统计连通块节点数的问题

方法简单

dfs过一遍算每个点的总子树节点数s[z],那么对于一个点u,它的父亲v的节点数就是s[v]-s[u]

然后选出max(s[v]-s[u],s[son])中最小的那个点就是了

 

【树上边权最长路径】

解释:对于一棵树,找到两点,使他们路径上的边权和最大

方向一 LCA

Ⅱ 每次保存最长链

设d[i]为i节点到叶子的max值

d[i]=max{d[son]}+w[i]

但这样也基本算是枚举了

方向二 端点

Ⅰ最长链往下——思路如上

Ⅱ 最长链往上

2020正睿暑期班DAY1小结_第2张图片

 

 如果最长链往上,我们要判断就是到哪一位祖先为转折点

转折点一方面可以理解为停止不动了,到此为止了

另一方面则是表示为到这个发生转折,开始往下

往上的部分好搞,在Ⅰ的基础上乱搞就好

那么往下的呢?

往下的路径一定是要选尽量长的,保证答案的优秀

但是这时候我们发现,如果只选最长的,很有可能会和u-v冲突,也就是v最长链就是u-v,总不能再走一遍吧

所以我们维护一个次长链,如果最长链真的是u-v,那么我们就走次长链下去

以此选出max值

 

方向三 前缀

 

例题1

解析1

例题2

共有n门课,每门课有不同的学分,每门课没有或有唯一- 门直接的先修课程。问在修m课的前提下,能够获得的最大学分数是多少?

解析:要点 分组背包DP

dp[i][j]表示点i已选j个的最大学分

O(n3)

【树形背包】

 树形背包区别于普通背包的特点就是在于树形,节点之间有父子牵制关系。比方说选了父节点,才能选择子节点

一阶:n3

最基础,最好理解,每次遍历一个点的时候,先遍历它的儿子,然后再对每个儿子做背包

for(int i=0;i){
    int v=G[u][i];
    dfs(v,u);
    for(int j=m+1;j>=1;j--)//背包容量
        for(int k=m;k>0;k--)//每次的枚举值
            if(j-k<1) continue;
            dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]);
        }
}

二阶:n2

方法一  

一阶的问题呢,主要是出在dfs套背包,太大了,每次还要子节点搞一遍

那么我们对症下药,dfs序我们提前给它搞出来,然后按照dfs序积压就好

但事实上,这样的答案是累积到最后一个点的。

而且,我们可以记录它的下一个兄弟,即当当前这个点不选的时候,就可以把当前的价值先推给它的下一个兄弟

f[i][j]表示到第i个点取j个元素的答案

void Doit_dp() {
	for (int i = 1; i <= n; ++i)
		d[dfn[i]] = s[i];
	for (int i = 1; i <= n + 1; ++i)
		for (int j = 0; j <= m; ++j)
			f[i][j] = -Inf;
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= min(i, m); ++j) {
			upt(f[i + 1][j + 1], f[i][j] + d[i]);
			upt(f[nx[i]][j], f[i][j]);
		}
}

 

方法二

有些时候,我们的节点数完全没有达到我们设置的背包容量大小,那么为什么要浪费时间去跑呢

所以我们就设置成最大节点数了

这样的话按原来思路是按照树形DP的基本实现,由儿子累加到父亲

for(int i=0;i=1;j--)//背包容量
        for(int k=m;k>0;k--)//每次的枚举值
           g[j+k]=max(g[j+k],dp[v][k]+dp[u][j-k]);
    sz[u]+=sz[v];
	for(j=1;j<=sz[u];j++)
		dp[u][j]=max(dp[i][j],g[j]);    
}

 

例题4:

给出一棵n个节点的树,每个节点拥有一个颜色ci,现在定义两点之间的距离为其路径上出现过的不同颜色数量

解析:

 

例题5

给出一个n个节点的树,每个节点有点权ai 求最长的树上路径,满足路径上的节点点权的gcd和不等于1

n<=2e5  ai<=2e5

解析:

gcd不等于1,相当于所有点权中任意两个都不互质,即都能被某个质数整除

放大到全局,就是该树上路径至少能被一个质数p整除

通过这个结论,我们初步推导,f[i][p]表示为以i为根的子树中,能被p整除的最长链

但是,第二维范围太大,所以要考虑优化

我们再回到树上分析,无论以i为子树的答案中,是走lca还是往上传递,都是要经过当前的子树根节点

所以我们的质数p就可以限定在可以整除i的质数中

那么i有多少个质数可以被整除呢?考虑到最大范围为2e5,1-2e5中的数最多有6个(2*3*……*13=30030  2*3*……*17=510510)

每次转移的时候判断儿子和父亲的质因子是否相同,然后转移长度

注意

1.ans和dp的区别,dp[][]的值是以i为结束,而ans还要考虑到lca

2.初始化

3.答案

4.边界条件

5.循环范围——数组边界

 

例题7

有一颗点数为n的树,有边权。给一个0-n之内的正整数k,你要在这棵树中选择k个点染成黑色,其余为白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的收益

 

 

 

解析:

dp过程中维护或计算最大值

刚开始的问题所在是在于计算两两之间的答案值,但事实上,思维突破点在于v的贡献是已经确定的,黑点确定,白点确定,uv的贡献也是可以确定的了

2020正睿暑期班DAY1小结_第3张图片

 

 

 

dp[i][j]以i为根的子树,j个点被染成黑色的最大值,背包DP

 

例题8

给定一个n个点m条边的无向无环图,在尽量少的节点上放灯,使得所有边都与灯相邻

1.在灯总数最小的前提,2.两盏灯同时照亮边的数量大

 

解析;

dp[i][j][0/1]以i为根的子树中,用j盏灯且根节点选/不选的最大边数

1.只考虑目标1

2.知道了选的灯数

保证1的情况下算2的答案

 

1.自定义结构

2.k进制数

最小灯数*k+亮灯边数

我们将max两灯边数转化为min一灯边数,为了使两个条件可以同时取min

dp[u][0]=dp[v][1]+1

dp[u][1]=Σmin{dp[v]1,dp[v][0]+1}+k

数位DP

例题1

1-N中所有含有13且能被13整除的数的个数

解析:

2020正睿暑期班DAY1小结_第4张图片

 

 

 2020正睿暑期班DAY1小结_第5张图片

 

 

 例题2 

1-N转化为二进制之后数位中1的总数的乘积

解析:

不妨将题目转化为len_n中二进制位1的总数,数位dp

dp[i][j][0/1]表示第i位数位中有j个1和上界的关系中的方案数

第i位取0:dp[i-1][j][k]——dp[i][j][k|N_i]

第i位取1:dp[i-1][j][k*max(k,n[i])]——dp[i][j+1][k]

ans=∏dp[n][j][0]+dp[n][j][1]

 

例题3 定义一个十进制数N的权值F(N)为其各个数位乘上2^len之和

给出A B,问0~B中权值不超过F(A)的数的个数

解析:

考虑F(A)和B可以作为上界,加上数的位数没有别的限制

dp[i][j][0/1]第i位,贡献之和为j的方案数

ans=∑dp[0][j][1+0]

例题4 

给定两个正整数a和b,求在[a,b]中 的所有整数中有多少个数能够整除它自身的所有非零数位。

解析:

首先易分析是数位DP~

和非0数位有关,所以和1-9的出现有关;再者因为考虑整除,所以还要考虑mod9余数

但是状态数6e9,过不去

我们再考虑,比方说从mod9余数就可以推导到mod3余数

所以9!——lcm(1,2,……,9)=2050

继续由这个思路推导,如果当前已经出现了9,那么3的出现还是否有必要?所以约束可以等价转化为,出现了的数位的lcm|原数%2520,而2520的质因子只有48个

所以状态数再次下降

你可能感兴趣的:(2020正睿暑期班DAY1小结)