P8352-[SDOI/SXOI2022]小N的独立集【dp套dp】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P8352


1|1题目大意

给出一棵树,每个点的权值是[1,k]之间的一个数,对于i[1,nk]求令这棵树的最大独立集权值为i的方案数。

1n1000,1k5


1|2解题思路

考虑我们求最大独立集时的dp方程,设fi,0/1表示i选/不选时的子树最大权值和。

注意到它总共有n2k2种状态,不能拿来dp套dp维护。

继续挖掘一下性质,若fi,0fi,1,那么fi,1显然没有用,若fi,0+kfi,1那么fi,0也没有用,因为我们可以显然父节点不选择更优。

所以我们可以强制fi,1[fi,0,fi,0+k]这个范围,这样我们的状态数就只剩下nk2种了。

gi,j,x表示fi,0=j,fi,1=j+x的方案数,然后dp子树转移即可。

时间复杂度:O(n2k4)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1010,P=1e9+7; struct node{ int to,next; }a[N<<1]; int n,k,tot,siz[N],ls[N],ans[N*5],f[N][N*5][6],g[N*5][6]; void addl(int x,int y){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;return; } void Add(int &x) {x=(x>=P)?(x-P):x;} void dfs(int x,int fa){ siz[x]=0; for(int i=1;i<=k;i++)f[x][0][i]=1; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(y==fa)continue;dfs(y,x); for(int a=0;a<=siz[x];a++){ for(int b=0;b<=k;b++){ if(!f[x][a][b])continue; for(int c=0;c<=siz[y];c++) for(int d=0;d<=k;d++){ int A=a+c+d,B=a+b+c; B=B-A;if(B<0)B=0; Add(g[A][B]+=1ll*f[x][a][b]*f[y][c][d]%P); } } } siz[x]+=siz[y]+k; for(int a=0;a<=siz[x];a++) for(int b=0;b<=k;b++) f[x][a][b]=g[a][b],g[a][b]=0; } return; } int main() { // printf("%d\n",sizeof(f)>>20); // freopen("2.in","r",stdin); // freopen("2.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); addl(x,y);addl(y,x); } dfs(1,0); for(int a=0;a<=siz[1];a++) for(int b=0;b<=k;b++) Add(ans[a+b]+=f[1][a][b]); for(int i=1;i<=n*k;i++) printf("%d\n",ans[i]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16557128.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示