分析
本人感觉本题十分巧妙
由于题目中给的是完全二叉树,这引起了思考
为什么会给二叉树?保证每个节点转移只有两种情况?
为什么是完全二叉树?保证树高不超过`!
由于题目行走路线的特殊性:
假设以节点为根节点出发走
那么先走完的子树,
(有父亲的话)再回到的父亲的另一个儿子(他的兄弟)
走完兄弟之后,回到父亲的父亲的另一个儿子(父亲的兄弟)
以此类推。。。
由于以单个转移的话,十分的麻烦
所以我们会考虑到设计DP状态F[i][j]表示走完的子树,回到第
个祖先的最小花费
G[i][j]表示走完的子树,回到第
个祖先的另一个儿子的最小花费
(这个DP状态太巧妙了!)
加上完全二叉树这一个优美性质
我们可以每次确定根节点之后
按定顺序走完全程,累加结果即可
时间复杂度:
代码
//P4253
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define LL long long
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define FOR(i,A,B) for(LL i=A;i<=B;i++)
#define BOR(i,A,B) for(LL i=A;i>=B;i--)
#define Lowbit(X) (X & (-X))
#define Skip cout<<endl;
#define INF 0x3f3f3f3f3f3f3f3f
#define Rson (X<<1|1)
#define Lson (X<<1)
using namespace std;
const LL MaxN=2e5+10;
LL Total,Num[MaxN],Fa[MaxN];
LL Child[MaxN][2];
LL F[MaxN][21],G[MaxN][21];
LL Dist[MaxN][21];
LL Ans=INF;
inline void File() {
freopen(".in","r",stdin);
freopen(".out","w",stdout);
}
inline LL Bro(LL New,LL X) {
return (New>>(X-1))^1;
}
inline LL DFS() {
BOR(k,Total,1) {
if(!Child[k][0]) for(LL i=1;k>>(i-1);i++)
G[k][i]=(Dist[k][i]+Dist[Bro(k,i)][1])*Num[Bro(k,i)];
else if(!Child[k][1]) for(LL i=1;k>>(i-1);i++)
G[k][i]=Dist[Child[k][0]][1]*Num[Child[k][0]]+G[Child[k][0]][i+1];
else for(LL i=1;k>>(i-1);i++)
G[k][i]=min(Dist[Child[k][0]][1]*Num[Child[k][0]]+G[Child[k][0]][1]+G[Child[k][1]][i+1],Dist[Child[k][1]][1]*Num[Child[k][1]]+G[Child[k][1]][1]+G[Child[k][0]][i+1]);
}
BOR(k,Total,1) {
if(!Child[k][0]) for(LL i=1;k>>(i-1);i++)
F[k][i]=Dist[k][i]*Num[k>>i];
else if(!Child[k][1]) for(LL i=1;k>>(i-1);i++)
F[k][i]=F[Child[k][0]][i+1]+Dist[Child[k][0]][1]*Num[Child[k][0]];
else for(LL i=1;k>>(i-1);i++)
F[k][i]=min(Dist[Child[k][0]][1]*Num[Child[k][0]]+G[Child[k][0]][1]+F[Child[k][1]][i+1],Dist[Child[k][1]][1]*Num[Child[k][1]]+G[Child[k][1]][1]+F[Child[k][0]][i+1]);
}
FOR(k,1,Total) {
LL Sum=F[k][1];
for(LL i=1,Fa=(k>>1);Fa;i++,Fa>>=1) {
LL Other=Bro(k,i);
if(Other>Total) Sum+=Dist[Fa][1]*Num[Fa>>1];
else Sum+=Dist[Other][1]*Num[Other]+F[Other][2];
}
Ans=min(Ans,Sum);
}
return Ans;
}
signed main() {
// File();
ios::sync_with_stdio(false);
cin>>Total;
FOR(i,1,Total) { cin>>Num[i]; }
FOR(i,2,Total) { cin>>Dist[i][1]; }
FOR(i,1,(Total>>1)+1) {
if((i<<1)<=Total) Child[i][0]=(i<<1);
else break;
if((i<<1|1)<=Total) Child[i][1]=(i<<1|1);
}
FOR(i,2,20) for(LL k=Total;k>>i;k--)
Dist[k][i]=Dist[k][i-1]+Dist[k>>(i-1)][1];
cout<<DFS()<<endl;
// fclose(stdin);
// fclose(stdout);
//system("pause");
return 0;
} 
京公网安备 11010502036488号