CF23 E. Tree 树形dp+高精度

题目链接

CF23 E. Tree

题解

CF竟让卡常QAQ
dp+高精度
dp[x][j]表示以x为根的子树,x所属的联通块大小为j,的最大乘积(不带j这块
最后f[x]维护以x为根的子树的最大答案
有点卡内存...高精压了4位
看了题解,了解到,其实这个dp的复杂度其实是O(n^2)
每次转移是复杂度是x之前的子树的sz * 当前子树的sz
相当于之前子树所有点和当前子树的点组成的点对数
而每个点对只会在lca处被计算一次
所以复杂度O(n^2)

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
inline int read() { 
	int x = 0,f = 1; 
	char c = getchar(); 
	while(c < '0' ||c > '9')c = getchar(); 
	while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
	return x * f; 
} 


const int L = 10000; 
const int maxn = 701; 
const int maxlen = 61; 
struct Bignum{ 
	int num[maxlen]; 
	int len; 
	Bignum () {memset(num,0,sizeof num); len = 0; }  
	void print() {
		for(int i = len;i;-- i) 
			if(i != len) { 
				if(num[i - 1] < L / 10) { 
					printf("0"); 
					if(num[i - 1] < L / 100) {
						printf("0"); 
						if(num[i - 1] < L / 1000) printf("0"); 
					} 
				} 
				printf("%d",num[i - 1]); 
			} else printf("%d",num[i - 1]);  
		puts(""); 
	} 
} dp[maxn][maxn],Max[maxn]; 

Bignum operator * (Bignum a,Bignum b) { 
	int len = 0; 
	Bignum ret; 
	for(int i = 0;i < a.len;i ++) for(int j = 0;j < b.len;j ++) { 
		ret.num[i + j] += a.num[i] * b.num[j]; 
		if(ret.num[i + j] >= L) {  
	 		ret.num[i + j + 1] += ret.num[i + j] / L; 
			ret.num[i + j] %= L;	
	 	} 
	}  
	len = a.len + b.len; 
	while(ret.num[len-1] == 0 && len > 1) len --; 
	ret.len = len; 
	return ret; 
} 
Bignum operator / (Bignum a,int b) { 
	int len = a.len; 
	Bignum ret; 
	if(!b) return ret; 
	for(int i = 0;i < len;i ++) { 
		ret.num[i] += a.num[i]* b;  
		if(ret.num[i] >= L)  { 
			ret.num[i+1] += ret.num[i] / L; 
			ret.num[i] %= L; 
		} 
	} 
	while(ret.num[len] > 0)  ret.num[len+1] = ret.num[len] / L, ret.num[len ++] %= L; 
	ret.len = len;
	return ret;
} 
Bignum max(Bignum a,Bignum b)  { 
  	if(a.len < b.len) return b; 
	if(a.len > b.len) return a; 
	for(int i = a.len-1;i >= 0;i --) {  
		if(a.num[i] < b.num[i]) return b; 
		if(a.num[i] > b.num[i]) return a;  
 	} 
 	return b; 
} 

//------------------------------- 
struct node { 
	int v,next;
}  edge[maxn << 1]; 
int head[maxn],num = 0; 
inline void add_edge(int u,int v) { 
	edge[++ num].v = v;edge[num].next = head[u];head[u] = num; 
}  int n; 
int siz[maxn]; 
void dfs(int x,int fa) { 
	siz[x] = 1; 
	dp[x][1].len = 1; dp[x][1].num[0] = 1; 
	for(int i = head[x];i;i = edge[i].next) { 
		int v = edge[i].v; 
		if(v == fa) continue; 
		dfs(v,x); 
		siz[x] += siz[v]; 
	} 
	for(int i = head[x];i;i = edge[i].next) { 
		int v = edge[i].v; 
		if(v == fa) continue; 
		for(int i = siz[x];i;-- i) { 
			if(dp[x][i].len)  
				for(int j = 1;j <= siz[v];++ j) 
					if(dp[v][j].len) dp[x][i + j] = max(dp[x][i + j],dp[x][i] * dp[v][j]); 
			dp[x][i] = dp[x][i] * Max[v]; 
		} 
	} 
	for(int i = siz[x];i ;-- i) Max[x] = max(Max[x],dp[x][i] / i); 
} 

int main() { 
	n = read(); 
	for(int i = 1,u,v;i < n;++ i) { 
		u = read();v = read(); 
		add_edge(u,v); add_edge(v,u); 
	}   
	dfs(1,0); 
	Max[1].print(); 
posted @ 2018-08-08 21:10  zzzzx  阅读(312)  评论(0编辑  收藏  举报