在网上翻了几篇博客没看懂,自己强行开码,于是就写篇博客希望对别的“走投无路”的人有所帮助
心路历程:
普及+的题目,不知道当时自己在想什么,dp式倒是推对了,然而优化不了空间,惨痛RE,然后钦定HNOI凉凉
题意:
设叶子结点到根结点,会经过i条未翻修的公路,j条未翻修的铁路
则叶子结点到根结点的贡献为(c[i]*(a[i]+i)*(b[i]+j))
设计方案控制(i,j)使(sum_{叶子结点i}c[i]*(a[i]+i)*(b[i]+j))最小
Solution
设(f[u][i][j])表示从根结点到结点u经过(i)条未翻修公路,(j)条未翻修铁路
的贡献最小值
于是有针对叶子结点(乡村),先预处理出
[f[u][i][j]=c[u]*(a[u]+i)*(b[u]+j)
]
然后是城市点(u)
当(u->v)选择修公路时,则右儿子会多经过一条未修的铁路
[f[u][i][j]=f[lson][i][j]+f[rson][i][j+1]
]
同理,当(u->v)选择修铁路时,则左儿子会多经过一条未修的公路
[f[u][i][j]=f[lson][i+1][j]+f[rson][i][j]
]
所以最终二者取(min)
(f[u][i][j]=min(f[lson][i][j]+f[rson][i][j+1],f[lson][i+1][j]+f[rson][i][j]);)
然后是值得注意的细节
1.(f[u][i][j])开(long long),然后中间叶子结点相乘时开1LL
2.本题卡空间,(f[u][i][j]) 中的一维(u)是不能开到20000的,这显然MLE,但是我们注意到上述dp再处理过程中,是一定先把儿子处理完才处理的自己,又由于这是一颗满二叉树,所以它相当于每次处理一条链,链与链之间的不影响,所以可以定义(dfn[u])表示点在链中映射的结点编号,然后只需要开到80就够了(恐怕这就是这个题目唯一有价值的地方了吧)
最后是激动人心的上代码过程
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
#define rg register
const int _=40100;
inline int read()
{
rg char ch='!';rg int z=1,num=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')z=-1,ch=getchar();
while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
return z*num;
}
int n,a[_],b[_],c[_];
struct ed{int to,next;}e[_<<1];
vector<int>g[_];
int cnt,head[_];
inline void link(int u,int v){e[++cnt]=(ed){v,head[u]};head[u]=cnt;}
int sz[_],dep[_],dfn[_];
ll f[105][45][45];
void dfs(int u,int k)
{
dfn[u]=k;
sz[u]=1;
for(rg int i=head[u];i;i=e[i].next)
{
rg int v=e[i].to;
dep[v]=dep[u]+1;
g[u].push_back(v);
if(g[u][1])dfs(v,k+2);
else dfs(v,k+1);
sz[u]+=sz[v];
}
if(sz[u]==1)
for(rg int i=0;i<=dep[u];++i)
for(rg int j=0;j<=dep[u];++j)
f[dfn[u]][i][j]=1ll*c[u]*(a[u]+i)*(b[u]+j);
else
for(int i=0;i<=dep[u];++i)
for(int j=0;j<=dep[u];++j)
f[dfn[u]][i][j]=min(f[dfn[g[u][0]]][i][j]+f[dfn[g[u][1]]][i][j+1],f[dfn[g[u][0]]][i+1][j]+f[dfn[g[u][1]]][i][j]);
}
int main()
{
memset(f,63,sizeof(f));
n=read();
for(rg int x,y,i=1;i<n;++i)
{
x=read(),y=read();
if(y<0)link(i,-y+n-1);
else link(i,y);
if(x<0)link(i,-x+n-1);
else link(i,x);
}
for(rg int i=n;i<=2*n-1;++i)a[i]=read(),b[i]=read(),c[i]=read();
dep[1]=0;dfs(1,0);
printf("%lld
",f[dfn[1]][0][0]);
return 0;
}