zoukankan      html  css  js  c++  java
  • day11-蒋明润

    T2 AT4995 [AGC034E] Complete Compress

    给你一颗 n 个节点的树,并用二进制串告诉你哪些节点上有棋子(恰好一颗)。

    可以进行若干次操作,每次操作可以将两颗距离至少为 2 的棋子向中间移动一步。

    问能否通过若干次操作使得所有的棋子都在一个点上,如果能,输出最小操作次数,如果不能,输出 -1 。

    2<= n <= 2000

    第一步,先枚举最后所有的棋子汇聚到了哪个点;

    然后,考虑树形dp,dp[i] 表示i的子树内最多能消掉多少对。

    考虑这样一个东西,有很多堆石子,它们的数量之和是sum,其中,最大的一堆是max。

    sum - max >= max 那么可以消掉所有的,也就是 (frac{sum}{2}) 对。

    否则 , 会消掉 sum - max 对,剩下 max * 2 - sum 个;

    在树上dp的时候也用上这个即可,然后剩下的那max * 2 - sum 个可以试着让最大的那个子树(也就是max属于的那个子树)消掉。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long LL;
    const int N = 2010;
    inline int read()
    {
    	register int x = 0 , f = 0; register char c = getchar();
    	while(c < '0' || c > '9') f |= c == '-' , c = getchar();
    	while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
    	return f ? -x : x;
    }
    int n , cnt;
    char s[N];
    int a[N] , siz[N] , sum[N] , f[N] , head[N];
    struct edge{ int v , nex; }e[N << 1];
    inline void add(int u , int v) { e[++cnt].v = v; e[cnt].nex = head[u]; head[u] = cnt; }
    
    void dfs(int x , int fa)
    {
    	siz[x] = a[x]; int mp = 0;
    	for(int i = head[x] , v; i ; i = e[i].nex)
    	{
    		v = e[i].v; if(v == fa) continue; dfs(v , x);
    		siz[x] += siz[v]; sum[v] += siz[v]; sum[x] += sum[v]; // sum[v] += siz[v] 得到这个子树内的距离和,必须的。 
    		if(sum[mp] < sum[v]) mp = v;
    	}
    	if(!mp) { f[x] = 0; return ; }
    	if(sum[x] - sum[mp] >= sum[mp]) f[x] = sum[x] / 2;
    	else f[x] = sum[x] - sum[mp] + min(f[mp] , (2 * sum[mp] - sum[x]) / 2);
    }
    
    int calc(int rot)
    {
    	for(int i = 1 ; i <= n ; ++i) f[i] = siz[i] = sum[i] = 0;
    	dfs(rot , 0); if((sum[rot] & 1) || (f[rot] * 2 < sum[rot])) return 2e9;
    	return sum[rot] / 2;
    }
    
    int main()
    {
    	n = read(); scanf("%s" , s+1);
    	for(int i = 1 ; i <= n ; ++i) a[i] = s[i] - '0';
    	int u , v;
    	for(int i = 1 ; i <  n ; ++i) u = read() , v = read() , add(u , v) , add(v , u);
    	int ans = 2e9;
    	for(int i = 1 ; i <= n ; ++i) ans = min(ans , calc(i));
    	cout << (ans == 2e9 ? -1 : ans) << '
    '; 
    	return 0;
    }
    
  • 相关阅读:
    0302思考并回答一些问题
    1231 实验四 递归下降语法分析程序设计
    1118 实验三 有限自动机的构造与识别
    1112对他人的博客评论及建议
    1029c语言文法
    1022词法分析实验总结
    词法分析
    0330 复利计算——单元测试
    0321 读《构建之法》第一,二,三章有感
    0316 复利计算总结(0330 更新)
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/13051119.html
Copyright © 2011-2022 走看看