【YbtOJ#20064】预算缩减
题目
题目链接:http://noip.ybtoj.com.cn/contest/90/problem/2
给定一棵树,你需要删去一些边(可以不删),使得剩下的图中每个点所在的连通块大小都 。
求删边的方案数,对 取模。两种方案不同,当且仅当存在一条边在一个方案中被删去,而在另外一个方案中没有被删去。
思路
设 表示在 子树中, 所在连通块大小为 ,其他联通块大小全部不小于 的方案数。
考虑加入一棵子树 的时候,有
其中变量只需要枚举到子树大小,这样复杂度等价于枚举了子树的两个点,而每两个点在 LCA 处才会被枚举。时间复杂度 。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5010,MOD=786433;
int n,m,tot,head[N],size[N];
ll ans,f[N][N],g[N];
struct edge
{
int next,to;
}e[N*2];
void add(int from,int to)
{
e[++tot].to=to;
e[tot].next=head[from];
head[from]=tot;
}
void dfs(int x,int fa)
{
size[x]=f[x][1]=1;
for (int i=head[x];~i;i=e[i].next)
{
int v=e[i].to;
if (v!=fa)
{
dfs(v,x);
for (int j=1;j<=size[x]+size[v];j++)
g[j]=f[x][j],f[x][j]=0;
for (int j=1;j<=size[x];j++)
for (int k=1;k<=size[v];k++)
{
f[x][j+k]=(f[x][j+k]+f[v][k]*g[j])%MOD;
if (k>=m) f[x][j]=(f[x][j]+f[v][k]*g[j])%MOD;
}
size[x]+=size[v];
}
}
}
int main()
{
freopen("cut.in","r",stdin);
freopen("cut.out","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for (int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(1,0);
for (int i=m;i<=n;i++)
ans=(ans+f[1][i])%MOD;
printf("%lld",ans);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理