正题
nowcoder 1103-B
题目大意
给你一棵树,让你找两条不交的链,长度分别为a,b,问有多少中方案
解题思路
设fx,0∼3,yf_{x,0\sim 3,y}fx,0∼3,y为在x的子树中,第1/2条链连了y条边,另一条链连完了/没连
然后对于每个儿子考虑作为什么计算,直接DP
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 3010
using namespace std;
ll n,a,b,x,y,tot,f[N][4][N],h[N];
struct rec
{ll to,nx;
}e[N<<1];
void add(ll x,ll y)
{e[++tot].to=y;e[tot].nx=h[x];h[x]=tot;
}
void dfs(ll x,ll fa)
{f[x][0][0]=1;f[x][1][0]=1;ll num,num1=0,num2=0;for(ll i=h[x];i;i=e[i].nx){ll y=e[i].to;if(y==fa)continue;dfs(y,x);num=0;for(ll j=1;j<=a;++j){if(j<a){//由两个儿子直接构成链f[x][0][a]+=f[x][0][j]*f[y][0][a-j-1];num+=f[x][0][j]*f[y][0][a-j-1];f[x][2][a]+=f[x][2][j]*f[y][0][a-j-1]+f[x][0][j]*f[y][2][a-j-1];}f[x][0][j]+=f[y][0][j-1];//练到父亲f[x][2][j]+=f[y][2][j-1]+f[y][0][j-1]*num2;//之前可以构成另一条链的}f[x][2][0]+=f[y][1][b];for(ll j=1;j<a;++j)f[x][2][j]+=(f[x][0][j]-f[y][0][j-1])*f[y][1][b];//同一条链只能使用一次f[x][2][a]+=(f[x][0][a]-f[y][0][a-1]-num)*f[y][1][b];num=0;for(ll j=1;j<=b;++j){if(j<b){f[x][1][b]+=f[x][1][j]*f[y][1][b-j-1];num+=f[x][1][j]*f[y][1][b-j-1];f[x][3][b]+=f[x][3][j]*f[y][1][b-j-1]+f[x][1][j]*f[y][3][b-j-1];}f[x][1][j]+=f[y][1][j-1];f[x][3][j]+=f[y][3][j-1]+f[y][1][j-1]*num1;}f[x][3][0]+=f[y][0][a];for(ll j=1;j<b;++j)f[x][3][j]+=(f[x][1][j]-f[y][1][j-1])*f[y][0][a];f[x][3][b]+=(f[x][1][b]-f[y][1][b-1]-num)*f[y][0][a];f[x][0][a]+=f[y][0][a];num1+=f[y][0][a];f[x][1][b]+=f[y][1][b];num2+=f[y][1][b];f[x][2][a]+=f[y][2][a];f[x][3][b]+=f[y][3][b];}
}
int main()
{scanf("%lld%lld%lld",&n,&a,&b);for(ll i=1;i<n;++i){scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}dfs(1,0);printf("%lld",(f[1][2][a]+f[1][3][b])*4);return 0;
}