题解:P11179 [ROIR 2018 Day1] 管道监控
秒秒题。没有题解呢,来发一发。建议降蓝。
思路
发现往下匹配路径不好处理,于是反转每个路线的字符串,然后从下往上移动覆盖,这样定了一个方向。
若只输出最小值,就从下往上 dp,发现可以 $n^3$ 处理,猜测正解设两维状态,$\Theta(n)$ 合并。第一维肯定是当前节点 $x$ 为根的子树内的所有边都被覆盖完,第二维容易想到是节点 $x$ 往上的 $k$ 个节点也被覆盖到了。设当前节点有儿子 $u$,容易有转移:$f_{x,\max(i,j)} \to f_{x,i}+f_{u,j+1} $,转移方式为取 $\min$。
于是直接 dp 即可。如果要输出方案,直接对于每个状态存储方案,由于最终路线 $n$ 条就可以覆盖完,所以可以直接存储。
代码:
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/rope>
#define rep(i,l,r) for(int i=(l),i##end=(r);i<=i##end;++i)
#define per(i,r,l) for(int i=(r),i##end=(l);i>=i##end;--i)
#define int long long
#define double long double
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define rbtree(way) tree<way,null_type,less<way>,rb_tree_tag,tree_order_statistics_node_update>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
const int maxn=500+10,maxm=1e5+10,mod=998244353,inf=1e15;
inline int ksm(int x,int k,int mod=mod){int ans=1;for(;k;k>>=1,x=x*x%mod) if(k&1) ans=ans*x%mod;return ans;
}int n,m,opt,tot=1,fa[maxn],g[maxn],dep[maxn],f[maxn][maxn],tr[maxm*10][30];
pii ed[maxm*10];
vector<pii> dp[maxn][maxn],rmg[maxn];
char c[maxn];
vector<int> e[maxn];
string s[maxm];
void dfs(int x){rep(i,1,dep[x]) f[x][i]=inf;for(int u:e[x]){dep[u]=dep[x]+1,dfs(u);rep(i,0,n) g[i]=f[x][i],rmg[i]=dp[x][i],f[x][i]=inf,dp[x][i].clear();rep(i,0,dep[x]) rep(j,0,dep[x]) f[x][max(i,j)]=min(f[x][max(i,j)],g[i]+f[u][j+1]);rep(i,0,dep[x]) rep(j,0,dep[x]) if(f[x][max(i,j)]<inf&&f[x][max(i,j)]==g[i]+f[u][j+1]&&!dp[x][max(i,j)].size()) dp[x][max(i,j)]=rmg[i],dp[x][max(i,j)].insert(dp[x][max(i,j)].end(),dp[u][j+1].begin(),dp[u][j+1].end());}for(int i=x,k=0,nw=1,tmp=0;i&&nw;nw=tr[nw][c[i]-'a'],i=fa[i],++k){if(ed[nw].fi+f[x][tmp]<f[x][k])f[x][k]=ed[nw].fi+f[x][tmp],dp[x][k]=dp[x][tmp],dp[x][k].pb({x,ed[nw].se});if(f[x][k]<f[x][tmp]) tmp=k;}
}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m>>opt;rep(i,2,n) cin>>fa[i]>>c[i],e[fa[i]].pb(i);rep(i,1,m){int val,nw=1;cin>>val>>s[i],reverse(s[i].begin(),s[i].end());for(char c:s[i]) !tr[nw][c-'a']?ed[tr[nw][c-'a']=++tot]={inf,0},0:0,nw=tr[nw][c-'a'];ed[nw]=min(ed[nw],{val,i});}dfs(1);if(f[1][0]>=inf) return cout<<-1,0;cout<<f[1][0]<<'\n';if(opt==1){cout<<dp[1][0].size()<<'\n';for(pii x:dp[1][0]){int k=x.fi;rep(i,1,s[x.se].size()) k=fa[k];cout<<k<<" "<<x.fi<<" "<<x.se<<"\n";}}return 0;
}