CF1369D TediousLee 题解(树形DP+递推)

题目链接

个人认为是一道非常有意思的题,题意就不赘述了

首先,要发现这题的做法,必须要先打表找规律。可以自己在纸上用手捏出 n ≤ 6 n\le 6 n6 的数据

经过打表后,我们可以发现下面这个规律:

CF1369D TediousLee 题解(树形DP+递推)_第1张图片

图稍微有点丑,见谅

这里其实很像树的最大独立集,我们可以用树形DP实现
f [ x ] [ 0 ] f[x][0] f[x][0] 为以 x x x 为根的子树中,不选 x x x 的情况下可以得到的最多的 claw 的数量。注意这里是 claw 的数量,不是染成黄色的节点数
同理,设 f [ x ] [ 1 ] f[x][1] f[x][1] 为选 x x x 的情况下可以得到的最多的 claw 的数量。那么,转移方程就是:
f [ x ] [ 1 ] = ∑ f [ y ] [ 0 ] f[x][1]=\sum f[y][0] f[x][1]=f[y][0] f [ x ] [ 0 ] = ∑ max ⁡ ( f [ y ] [ 1 ] , f [ y ] [ 0 ] ) f[x][0]=\sum \max(f[y][1],f[y][0]) f[x][0]=max(f[y][1],f[y][0]),其中 y y y x x x 的儿子

但是, T ≤ 1 0 4 , n ≤ 2 ⋅ 1 0 6 T\le 10^4,n\le 2 \cdot 10^6 T104,n2106 的数据范围并不允许。

根据上面的打表,相信你们一定会发现每一个级别对应着一个唯一的 RDB,又因为 n ≤ 2 ⋅ 1 0 6 n\le 2 \cdot 10^6 n2106,所以我们可以用递推或者记忆化搜索实现(下面的 f f f 跟上面的没有关系)

f [ i ] [ 1 ] f[i][1] f[i][1] 为在级别为 i i i RGB 中,如果选上根节点时最多可以选出多少个 claw
同理 f [ i ] [ 0 ] f[i][0] f[i][0] 表示不选根节点时最多可以选出的 claw 的个数
转移方程: f [ i ] [ 1 ] = 2 × f [ i − 2 ] [ 0 ] + f [ i − 1 ] [ 0 ] + 1 f[i][1]=2 \times f[i-2][0]+f[i-1][0]+1 f[i][1]=2×f[i2][0]+f[i1][0]+1
f [ i ] [ 0 ] = 2 × max ⁡ ( f [ i − 2 ] [ 0 ] , f [ i − 2 ] [ 1 ] ) + max ⁡ ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] ) f[i][0]=2 \times \max(f[i-2][0],f[i-2][1])+\max(f[i-1][0],f[i-1][1]) f[i][0]=2×max(f[i2][0],f[i2][1])+max(f[i1][0],f[i1][1])

时间复杂度 O ⁡ ( n ) \operatorname{O}(n) O(n)

#include
#include
using namespace std;
const int Maxn=2000000+10,mod=1000000007;
int f[Maxn][2];
int n,m;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
int main()
{
//	freopen("in.txt","r",stdin);
	int T=read();
	m=2;
	while(T--)
	{
		n=read();
		if(m<n)
		for(int i=m+1;i<=n;++i)
		{
			f[i][1]=((f[i-2][0]<<1)%mod+f[i-1][0]+1)%mod;
			int tmp=(max(f[i-2][0],f[i-2][1])<<1)%mod;
			f[i][0]=(tmp+max(f[i-1][0],f[i-1][1]))%mod;
		}
		m=max(n,m);
		int ans=max(f[n][0],f[n][1]);
		ans=(ans<<1)%mod;
		ans=(ans<<1)%mod; // 输出的时候记得乘以4!
		printf("%d\n",ans);
	}
	return 0;
}

好像还可以用矩乘做,后续可能会更新矩乘的做法

你可能感兴趣的:(题解,#Codeforces,树形DP,记忆化搜索,递推)