【xsy1120】 支援(assist) dp+卡常
妙啊算错时间复杂度了
题目大意:给你一棵n个节点的二叉树,每个节点要么是叶子节点,要么拥有恰好两个儿子。
令m为叶子节点个数,你需要在这棵二叉树中选择i个叶子节点染色,叶节点染色需要一定的代价,非叶子节点代价为两孩子的染色节点数量的异或和乘上一常数。请最小化代价。
数据范围:n≤4000。
显然这是一道dp题。
令f[u][i]表示在以u号点为根的子树中,选择i个叶子节点染色的最小代价。
若u为叶子节点,不难得出f[u][0]=0,f[u][1]=c[u]。
我们不难得出f[u][i+j]=minf[lc][i]+f[rc][j]+c[u]∗(i xor j),其中lc,rc表示u的左儿子和右儿子,c[u]表示u号节点的常数。
然后这个dp转移,看似是O(n3)的,实际上:
T(n)=2T(n2)+O(n2)。这个实际上还是O(n2)的。。。。。。。。
然后就愉快地做完了,注意卡常。
1 #include<bits/stdc++.h> 2 #define M 4005 3 #define L long long 4 #define INF (1<<28) 5 using namespace std; 6 int l[M]={0},r[M]={0},siz[M]={0},c[M]={0},vis[M]={0},f[M][M]={0}; 7 8 void dfs(int x){ 9 if(vis[x]) return; vis[x]=1; 10 if(l[x]==0&&r[x]==0){ 11 siz[x]=1; 12 f[x][0]=0; f[x][1]=c[x]; 13 return; 14 } 15 dfs(l[x]); dfs(r[x]); 16 siz[x]=siz[l[x]]+siz[r[x]]; 17 for(int i=0;i<=siz[l[x]];i++){ 18 for(int j=0;j<=siz[r[x]];j++) 19 f[x][i+j]=min(f[x][i+j],f[l[x]][i]+f[r[x]][j]+c[x]*(i^j)); 20 } 21 } 22 23 int Main(){ 24 memset(vis,0,sizeof(vis)); 25 int n; scanf("%d",&n); 26 for(int i=1;i<=n;i++) scanf("%d%d",l+i,r+i); 27 for(int i=1;i<=n;i++) scanf("%d",c+i); 28 for(int i=1;i<=n;i++) memset(f[i],63,(n+1)<<2); 29 for(int i=1;i<=n;i++) dfs(i); 30 int rt=0; for(int i=1;i<=n;i++) if(siz[rt]<siz[i]) rt=i; 31 for(int i=1;i<=siz[rt];i++) 32 printf("%d ",f[rt][i]); 33 printf("\n"); 34 } 35 int main(){ 36 int cas; cin>>cas; 37 while(cas--) Main(); 38 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!