【UVALive4685-Succession】树形DP
http://acm.hust.edu.cn/vjudge/problem/14338
题意:给定一棵树,每个点有一个值,让你选择k个点,并且这k个点是连在一起的(从任意一个点出发,可以遍历完所有选择的点 并且 不经过没有被选择的点),让这k个点的价值总和最大,纹方案数(Mod1000000007)。
题解:设d[x][k]为必须选择x,以x为根的子树中共选择了k个节点,价值总和最大是多少。
f[x][k]为d[x][k]对应的方案数是多少。
对于x,我们把x的孩子son不断地并到f[x]中。
对于每一个son:d[x][j]=maxx(d[x][j-k],d[son][k]);
需要注意的就是上式中d[x][j]不断地变化,对于当前的son,j变大的时候可能用到的d[x][j-k]是用当前的son更新的。所以要开一个p[x][j]等于当前的son没更新x的时候d[x][j]的值,同理q[x][j]=f[x][j]。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7
8 typedef long long LL;
9 const int N=110;
10 const LL Inf=(LL)1e9,Mod=1000000007;
11 struct node{
12 int x,y,next;
13 }a[2*N];
14 int len,n,m,r;
15 int first[N],son[N],w[N];
16 LL a1,a2,d[N][N],f[N][N],p[N][N],q[N][N];
17
18 void ins(int x,int y)
19 {
20 len++;
21 a[len].x=x;a[len].y=y;
22 a[len].next=first[x];first[x]=len;
23 }
24
25 void dfs(int x,int fa)
26 {
27 son[x]=1;
28 for(int i=first[x];i;i=a[i].next)
29 {
30 int y=a[i].y;
31 if(y==fa) continue;
32 dfs(y,x);
33 son[x]+=son[y];
34 }
35 }
36
37 void copy(int x)
38 {
39 for(int i=0;i<=n;i++) p[x][i]=d[x][i],q[x][i]=f[x][i];
40 }
41
42 void dp(int x,int fa)
43 {
44 for(int i=1;i<=n;i++) d[x][i]=-Inf;
45 memset(f[x],0,sizeof(f[x]));
46 d[x][0]=0;f[x][0]=1;d[x][1]=w[x];f[x][1]=1;
47
48 copy(x);
49
50 for(int i=first[x];i;i=a[i].next)
51 {
52 int y=a[i].y;
53 if(y==fa) continue;
54 dp(y,x);
55 for(int j=2;j<=son[x];j++)
56 {
57 for(int k=1;k<=son[y] && (j-k)>=1;k++)
58 {
59 LL dd=p[x][j-k]+d[y][k];
60 LL ff=(q[x][j-k]*f[y][k])%Mod;
61 if(dd > p[x][j])
62 {
63 if(dd>d[x][j]) d[x][j]=dd,f[x][j]=ff;
64 else if(dd==d[x][j]) f[x][j]=(f[x][j]+ff)%Mod;
65 }
66 else if(dd == p[x][j])
67 {
68 if(dd==d[x][j]) f[x][j]=(f[x][j]+ff)%Mod;
69 }
70 }
71 }
72 copy(x);
73 }
74
75 if(d[x][m]>a1) a1=d[x][m],a2=f[x][m];
76 else if(d[x][m]==a1) a2=(a2+f[x][m])%Mod;
77 }
78
79 int main()
80 {
81 freopen("a.in","r",stdin);
82 // freopen("a.out","w",stdout);
83 int T;
84 scanf("%d",&T);
85 while(T--)
86 {
87 len=0;
88 memset(first,0,sizeof(first));
89 scanf("%d%d%d",&n,&m,&r);
90 for(int i=1;i<=n;i++) scanf("%d",&w[i]);
91 for(int i=1;i<=r;i++)
92 {
93 int x,y;
94 scanf("%d%d",&x,&y);
95 x++;y++;
96 ins(x,y);ins(y,x);
97 }
98 dfs(1,0);
99 a1=-Inf;
100 dp(1,0);
101 printf("%I64d %I64d\n",a1,a2);
102 }
103 return 0;
104 }