洛谷P3354 Riv河流 [IOI2005] 树型dp
正解:树型dp
解题报告:
简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离
首先这个一看就是个树型dp嘛,关键是怎么设状态
首先肯定是想到设f[i][j]:以i为根的子树中选了j个点
这个时候发现布星昂,这么设的时候我们不能得到对于到根的路径上的点的贡献鸭,所以就考虑加一维
所以f[i][j][k]:以i为根的子树中选了j个点,最近祖先的距离为k的最大代价
然后直接转移就好
对了还要说一个就,我这里有转点儿题意?就它是问最小化花费,然后我写题解的时候是转化成的tot-max∑
但实际实现的时候我是直着写的就是说直接最小化花费打的QAQ
差不多差不多QAQ
然后我发现我现在码力是真的弱,,,,我知道这题正解了,还是个dp题,然后打了2h?我原地自杀了要,,,
#include<bits/stdc++.h> using namespace std; #define il inline #define fr first #define sc second #define rg register #define gc getchar() #define ll long long #define mp make_pair #define rp(i,x,y) for(rg int i=x;i<=y;++i) #define my(i,x,y) for(rg int i=x;i>=y;--i) const int N=100+2,K=50+2; int n,k,w[N],stck_top,stck[N],dis[N]; ll f[N][K][N][2]; vector< pair<int,int> >son[N]; il int read() { rg char ch=gc;rg int x=0;rg bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il void dfs(int nw) { stck[++stck_top]=nw; int sz=son[nw].size(); rp(i,0,sz-1) { dis[son[nw][i].fr]=dis[nw]+son[nw][i].sc;dfs(son[nw][i].fr); my(j,stck_top,1) { my(p,k,0) { f[nw][p][stck[j]][0]+=f[son[nw][i].fr][0][stck[j]][0]; f[nw][p][stck[j]][1]+=f[son[nw][i].fr][0][nw][0]; my(q,p,0) { f[nw][p][stck[j]][0]=min(f[nw][p][stck[j]][0],f[son[nw][i].fr][q][stck[j]][0]+f[nw][p-q][stck[j]][0]), f[nw][p][stck[j]][1]=min(f[nw][p][stck[j]][1],f[son[nw][i].fr][q][nw][0]+f[nw][p-q][stck[j]][1]); } } } } rp(i,1,stck_top) { my(j,k,0) if(j)f[nw][j][stck[i]][0]=min(f[nw][j-1][stck[i]][1],f[nw][j][stck[i]][0]+w[nw]*(dis[nw]-dis[stck[i]])); else f[nw][j][stck[i]][0]+=w[nw]*(dis[nw]-dis[stck[i]]); } --stck_top; return; } int main() { // freopen("riv.in","r",stdin);freopen("riv.out","w",stdout); n=read();k=read(); rp(i,1,n){w[i]=read();int fa=read(),dis=read();son[fa].push_back(mp(i,dis));} dfs(0);printf("%lld\n",f[0][k][0][0]); return 0; }
顺便港下,这题有个双倍经验
都差不多只是还要建棵trie树就好了,over
等下把那题代码也放上来吼QwQ
#include<bits/stdc++.h> using namespace std; #define il inline #define fr first #define sc second #define rg register #define gc getchar() #define ll long long #define mp make_pair #define rp(i,x,y) for(rg int i=x;i<=y;++i) #define my(i,x,y) for(rg int i=x;i>=y;--i) const int N=500+2,K=10+2; int n,k,stck_top,stck[N],dis[N],nod_cnt; ll f[N][K][N][2],as; struct node{int to[10],wei;}tr[N*100]; il int read() { rg char ch=gc;rg int x=0;rg bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il void insert(string str,ll wei) { ll lth=str.length(),nw=0; rp(i,0,lth-1) { if(!tr[nw].to[str[i]^'0'])tr[nw].to[str[i]^'0']=++nod_cnt; nw=tr[nw].to[str[i]^'0'];tr[nw].wei+=wei; } } il void dfs(int nw) { stck[++stck_top]=nw; rp(i,0,9) { if(!tr[nw].to[i])continue;dis[tr[nw].to[i]]=dis[nw]+1;dfs(tr[nw].to[i]); my(j,stck_top,1) my(p,k,0) my(q,p,0) f[nw][p][stck[j]][0]=max(f[nw][p][stck[j]][0],f[tr[nw].to[i]][q][stck[j]][0]+f[nw][p-q][stck[j]][0]), f[nw][p][stck[j]][1]=max(f[nw][p][stck[j]][1],f[tr[nw].to[i]][q][nw][0]+f[nw][p-q][stck[j]][1]); } rp(i,1,stck_top) my(j,k,0) if(j)f[nw][j][stck[i]][0]=max(f[nw][j-1][stck[i]][1]+tr[nw].wei*(dis[nw]-dis[stck[i]]),f[nw][j][stck[i]][0]); --stck_top; return; } int main() { // freopen("sd.in","r",stdin);freopen("sd.out","w",stdout); n=read();k=read();rp(i,1,n){string str;cin>>str;ll wei=read();insert(str,wei);as+=str.length()*wei;} dfs(0);printf("%lld\n",as-f[0][k][0][0]); return 0; }