[USACO12FEB]附近的牛Nearby Cows
阿新 • • 發佈:2018-11-01
題目
https://www.luogu.org/problemnew/show/P3047
思路
首先,我們先定義狀態f[i][j]為i點在j步以內的所有奶牛數。
寫轉移方程時,我們很容易想到,將此狀態轉移至與自己連通的s節點的f[s][j-1]中。
可是,這樣會有一部分重複計算。因為每個s點向i點延伸1步後,還有j-2步其它方向繼續擴散。
所以我們只要再減掉重複位置,即f[i][j-2]*(連通節點個數-1)。“-1”是為了留下一次計算,不能全減完了。
狀態轉移方程就寫出來了:f[i][j]=f[s][j-1]-f[i][j-2]*(son[i]-1);
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #define Ll long long using namespace std; struct cs{ int to,next; }a[200001]; int head[100001],w[100001],fa[100001],f[100001][25];//w[i]表示i節點的值,fa[i]是i的父節點, int m,n,x,y,z,ll; void init(int x,int y){ ll++; a[ll].to=y; a[ll].next=head[x]; head[x]=ll; } void dfs(int x,int y){//當前是x點,其父節點是y fa[x]=y; f[x][0]=w[x]; for(int k=head[x];k;k=a[k].next) if(a[k].to!=y){ dfs(a[k].to,x); for(int j=1;j<=m;j++) f[x][j]+=f[a[k].to][j-1]; } } void cfb(int x){ int ans=0,k=m; ans=f[x][m]; while(x!=1&&k){ ans+=f[fa[x]][--k]; if(k)ans-=f[x][k-1]; x=fa[x]; } printf("%d\n",ans); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n-1;i++)scanf("%d%d",&x,&y),init(x,y),init(y,x); for(int i=1;i<=n;i++)scanf("%d",&w[i]); dfs(1,-1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)f[i][j]+=f[i][j-1]; for(int i=1;i<=n;i++)cfb(i); }