“难度题” 题解

在这里插入图片描述
模拟赛时遇见的一道题,个人感觉这道题忒棒了!
考场时,除了看出来这是道树形 D P DP DP题以外,也就只会打暴力了。
做这道题时,你会发现,直接按原意来 D P DP DP的话,特别麻烦,你得记录每个点所在的连通块的 s u m sum sum是多少,但因为是 1 e 9 1e9 1e9级别的,这个 D P DP DP状态肯定就不行了。那怎么办呢?既然这样 D P DP DP不行,那就换一种方式 D P DP DP
若是有经验的 d a l a o dalao dalao们肯定已经发现了。一个联通块的 s u m sum sum的平方,就相当于在 s u m sum sum个点中找到两个点 x , y x,y x,y x x x涂成红色, y y y涂成蓝色( x = = y x==y x==y是允许的)。这样的话,题意就可以改成:把一个树分成多个连通块,在每个连通块内找两点 x x x y y y分别涂成红色和蓝色的方案数。
D P DP DP状态: f [ x ] [ o p ] f[x][op] f[x][op]表示在 x x x为根的子树中, x x x所在的连通块中选了 o p op op个点涂色的方案数。
那么,接下来考虑一下DP方程:
设父亲为 u u u,儿子为 v v v,初值为: f [ x ] [ 0 ] = 1 , f [ x ] [ 1 ] = a [ x ] , f [ x ] [ 2 ] = a [ x ] ∗ a [ x ] f[x][0]=1,f[x][1]=a[x],f[x][2]=a[x]*a[x] f[x][0]=1,f[x][1]=a[x],f[x][2]=a[x]a[x]
然后,用 f [ v ] [ 0 ] , f [ v ] [ 1 ] 和 f [ v ] [ 2 ] 来 更 新 f[v][0],f[v][1]和f[v][2]来更新 f[v][0],f[v][1]f[v][2],这时候还需要引入一个变量 g g g,是用来 D P DP DP转移用的,为了防止被更新过的 f f f再次更新其他f值。
DP式子:

	for(int j = 0 ;j <= 2 ; j++) //父亲要涂几个 
		{
			for(int k = 0 ; k <= j ; k++)
			g[x][j] = (g[x][j] + f[x][j-k] *f[y][k] %p*c[j][k]) %p;//不断边 
			g[x][j] = (g[x][j] + f[y][2] * f[x][j] %p ) %p;//断边 
		}
		for(int i = 0 ; i <= 2 ; i++)
		f[x][i] = g[x][i] , g[x][i] = 0;

上面的式子,一种是当前 u u u v v v之间的边断,一种是之间的边不断,然后,各自转移。然后,这个组合数的存在,是因为你要枚举涂的是哪个颜色,或者说,处理的是红色点在 u u u还是在 v v v这个问题。
还有一种 D P DP DP形式,不用考虑组合数,状态是: f [ u ] [ 0 ] 表 示 u 所 在 的 连 通 块 不 涂 色 的 方 案 , f [ u ] [ 1 ] 表 示 涂 一 个 红 色 点 的 方 案 , f [ u ] [ 2 ] 表 示 涂 一 个 蓝 色 点 的 方 案 , f [ u ] [ 3 ] 表 示 红 蓝 两 点 都 涂 的 方 案 f[u][0]表示u所在的连通块不涂色的方案,f[u][1]表示涂一个红色点的方案,f[u][2]表示涂一个蓝色点的方案,f[u][3]表示红蓝两点都涂的方案 f[u][0]uf[u][1]f[u][2]f[u][3]

怎么转移呢?
就看你们了。
再见。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值