P9481 (NOI2023 d2t1) 题解
StarLbright40 · · 题解
Dijkstra 什么的看不懂啦(
贡献一个 1kb 精品解法。
对于本题,显然有
由于本题没有横叉边,所以每对
对于
接下来我们处理
定义
首先考虑仅经过一条第二类边的情形。对于一条
再拓展到所有情形,发现这一过程与 Floyd 类似。从而枚举中转点同时注意使用恰当的枚举顺序即可。
时间复杂度为
#include<bits/stdc++.h>
using namespace std;
const int N=18,mod=998244353;const long long inf=1e18;
int n,m,a[1<<N],ans;long long dis[1<<N],sum[1<<N],f[1<<N][N];
int siz(int x){return (1<<(n-__lg(x)))-1;}
long long val(int x){return sum[x]+1ll*siz(x)*a[x];}
int main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n>>m;
for(int i=2;i<1<<n;++i)
cin>>a[i],dis[i]=dis[i>>1]+a[i];
for(int i=(1<<n)-1;i>1;--i)
sum[i>>1]+=val(i);
memset(f,63,sizeof(f));
for(int u,v,w;m--;){
cin>>u>>v>>w;
for(int y=v;y>u;y>>=1) for(int x=y>>1;x>=u;x>>=1)
f[y][__lg(x)]=min(f[y][__lg(x)],w+dis[v]-dis[y]+dis[x]-dis[u]);
}
for(int u=1;u<1<<n;++u)
for(int i=__lg(u)-1,v=u>>1;v;--i,v>>=1) for(int j=i-1;~j;--j)
f[u][j]=min(f[u][j],f[u][i]+f[v][j]);
for(int u=(1<<n)-1;u;--u){
ans=(ans+sum[u])%mod;
for(int i=__lg(u)-1,v=u;v>1;--i,v>>=1) if(f[u][i]<inf)
ans=(ans+f[u][i]%mod*(siz(v)+1)+val(v^1))%mod;
}
cout<<ans;
return 0;
}