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 }
时间: 2024-10-11 17:32:53