• 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(); 
    
  • 相关阅读:
    5.14每日一题题解
    5.13 每日一题题解
    5.12 每日一题题解
    5.11 每日一题题解
    5.10每日一题题解
    【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】
    【POJ1509】Glass Beads 【后缀自动机】
    【codevs3160】 LCS 【后缀自动机】
    【HDU4734】F(x) 【数位dp】
    【hdu6148】Valley Numer【数位dp模板题】
  • 原文地址:https://www.cnblogs.com/sssy/p/9445707.html
Copyright © 2020-2023  润新知