Luogu【[HNOI/AHOI2018]道路】

在网上翻了几篇博客没看懂,自己强行开码,于是就写篇博客希望对别的“走投无路”的人有所帮助

心路历程:

普及+的题目,不知道当时自己在想什么,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\n",f[dfn[1]][0][0]);
    return 0;
}

posted @ 2018-07-01 08:49  龙神哈迪斯  阅读(145)  评论(0编辑  收藏  举报