首页 > 其他分享 >【题解】[SDOI/SXOI2022] 小 N 的独立集(dp of dp)

【题解】[SDOI/SXOI2022] 小 N 的独立集(dp of dp)

时间:2023-03-28 12:33:42浏览次数:45  
标签:SDOI int 题解 不选 edge now 转移 dp

题目分析:

就借助这个题稍微说一下 \(dp\) 套 \(dp\)。
对于 \(dp\) 套 \(dp\) 其解决的问题是:若给定某一具体情况则答案十分好求,现要求对于所有的情况的答案进行统计。
这类问题我们一般称解决这个具体情况的 \(dp\) 为内层 \(dp\),而对于所有情况进行统计的 \(dp\) 为外层 \(dp\)。
一般的解决方法是:将内层 \(dp\) 的状态直接扔到外层 \(dp\) 的下标上,然后再按需要加入一些新的下标,也就是说假设内层 \(dp\) 的状态为 \(f_1,f_2,f_3\),那么我们的外层 \(dp\) 则至少应为 \(g_{x,y,z}\),表示 \(f_1 = x,f_2 = y,f_3 = z\) 时统计的答案,转移时即按照内层 \(dp\) 的转移方式对于下标进行转移。
下面就以这个题为例看看 \(dp\) 套 \(dp\) 的具体应用。

看到这个题的第一眼就可以知道,若给定权值,则树上的最大权独立集是很好求的,就是直接设 \(f_{u,0/1}\) 表示以 \(u\) 为根的子树,\(u\) 节点不选/选的最大权独立集是多少。
考虑 \(f\) 的值并不大,所以可以使用 \(dp\) 套 \(dp\),即设 \(g_{u,i,j}\) 表示以 \(u\) 为根的子树 \(f_{u,0} = i,f_{u,1} = j\) 的方案数,那么转移就是显然的:(设 \(v\) 为 \(u\) 的儿子节点)

\[g_{u,i,j} \times g_{v,x,y} \to g_{u,i + \max(x,y),j+y} \]

根据树上背包的复杂度分析,这样直接做的复杂度为 \(O(n^4k^4)\)。
对于 \(dp\) 套 \(dp\) 常见优化就是压缩状态或者优化转移。
我们其实可以发现一条性质:\(f_{u,1}\) 不会比 \(f_{u,0}\) 大很多,虽然 \(f_{u,0}\) 可能比 \(f_{u,1}\) 大很多。
也就是说 \(\max(f_{u,1},f_{u,0})-f_{u,0}\) 不大,稍微分析一下就可以发现满足:\(0 \le \max(f_{u,0},f_{u,1}) - f_{u,0}\le val_u = k\)
因为 \(f_{u,0}\) 是在子树上按最优的方式转移的,即使 \(f_{u,1}\) 也是最优的方式转移也只会多 \(val_u\) 的贡献。
(注意这一行状态已经重新设计了)所以我们就可以将内层 \(dp\) 状态重新设计为:\(f_{u,0/1}\) 表示 \(u\) 节点不强制/强制不选的答案,\(g_{u,i,j}\) 表示 \(f_{u,1} = i,f_{u,0} = f_{u,1} + j\) 的方案数。
转移也是显然的:

\[g_{u,a,b} \times g_{v,c,d} \to g_{u,a+c+d,\max(a+c+d,a+b+c)-(a+c+d)} \]

这样的话复杂度就优化为了 \(O(n^2k^4)\)
需要注意一点就是 \(g_{u,i,j}\) 中 \(j\) 可以为 \(0\),因为显然不强制不选的最优答案可以为不选。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e3+5;
const int K = 7;
const int MOD = 1e9+7;
struct edge{
	int nxt,to;
	edge(){}
	edge(int _nxt,int _to){
		nxt = _nxt,to = _to;
	}
}e[2 * N];
int n,k,cnt,head[N],sz[N],g[N][N*K][K],f[N*K][K],ans[N*K];
//g[now][i][j] 表示 now 为根的子树,now 随意选不选权值为 i + j,now 强制不选权值为 i 的方案数 
void add_edge(int from,int to){
	e[++cnt] = edge(head[from],to);
	head[from] = cnt;
}
void dfs(int now,int fath){
	sz[now] = 1;
	for(int i=1; i<=k; i++)	g[now][0][i] = 1;
	for(int i=head[now]; i;i=e[i].nxt){
		int to = e[i].to;
		if(to == fath)	continue;
		dfs(to,now);memset(f,0,sizeof(f));
		for(int a=0; a<=sz[now]*k; a++){
			for(int b=0; b<=k; b++){
				if(g[now][a][b] == 0)	continue;
				for(int c=0; c<=sz[to]*k; c++){
					for(int d=0; d<=k; d++){
						f[a+c+d][max(a+b+c,a+c+d)-(a+c+d)] = (f[a+c+d][max(a+b+c,a+c+d)-(a+c+d)] + g[now][a][b] * g[to][c][d])%MOD;
						//其实转移就是正常的转移 
					}
				}
			}
		}
		memcpy(g[now],f,sizeof(f));
		sz[now] += sz[to];
	}
}
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%lld%lld",&n,&k);
	for(int i=1; i<n; i++){
		int from,to;scanf("%lld%lld",&from,&to);
		add_edge(from,to);add_edge(to,from);
	}
	dfs(1,0);
	for(int i=1; i<=n*k; i++){
		for(int j=0; j<=min(i,k); j++){
			ans[i] = (ans[i] + g[1][i-j][j])%MOD;
		}
	}
	for(int i=1; i<=n*k; i++)	printf("%lld\n",ans[i]);
	return 0;
}

标签:SDOI,int,题解,不选,edge,now,转移,dp
From: https://www.cnblogs.com/linyihdfj/p/17264653.html

相关文章

  • python apscheduler 定时任务的基本使用-8-线程执行器ThreadPoolExecutor
    pythonapscheduler定时任务的基本使用-8-线程执行器ThreadPoolExecutor1、线程执行器ThreadPoolExecutor先说个人总结假设启动线程数为N,任务数为M,misfire_grace_tim......
  • Fragmentation merging-填坑dp
    D.Fragmentationmerginghttps://codeforces.com/gym/103104/problem/D题意给定一个长度为n(\(n<=5e3\))的排列每次操作可以选择两个不相交的区间,如果两个区间并起来的......
  • 使用HBase EndPoint(coprocessor)进行计算
    如果要统对hbase中的数据,进行某种统计,比如统计某个字段最大值,统计满足某种条件的记录数,统计各种记录特点,并按照记录特点分类(类似于sql的groupby)~常规的做法就是把hbase中整......
  • 【题解】[HNOI2007]梦幻岛宝珠
    题目分析:对于这种某一个值很大另一个值很小的背包题,就是要求找特殊性质。既然每一个\(w\)都可以写成\(a\times2^b\)的性质,就可以对于每一个\(b\)单独做背包,这样......
  • 【题解】[APIO2010] 信号覆盖
    题目分析:其实就是涉及四个点之间的位置关系,三个点形成圆判断是否包含另一个点。考虑四个点之间形成的多边形只可能是凸四边形或者是凹四边形,如下图所示:(上图为凸多边形)......
  • 【题解】Atcoder ABC295 A-G
    A.ProbablyEnglish题目分析:直接每一个单词判一下就好了。代码:点击查看代码#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn;scanf("%d",&n); bo......
  • CF743B Chloe and the sequence 题解 分治
    题目链接:http://codeforces.com/problemset/problem/743/B题目大意:对于一个n-序列,如果n==0,那么它是一个空的序列(也就是说空序列中没有元素)。然后会进行i次操作,每次......
  • CF768B Code For 1 题解 分治
    题目链接:http://codeforces.com/problemset/problem/768/B解题思路:分治。本题和的解题思路相似。tips:如果如果\(n\)对应的区间完全被\([l,r]\)覆盖了,则区间\([......
  • leetcode-841-钥匙和房间 题解
    题目描述有N个房间,开始时你位于0号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。在形式上,对于每个房间i都有一个钥匙列表r......
  • 【ACM算法竞赛日常训练】DAY4题解与分析【树】【子序列】| 组合数学 | 动态规划
    DAY4共2题:树(组合数学)子序列(dp,数学)......