題解/算法 {6211. 创建价值相同的连通块}

oi-link

Solution

Let s u m sum sum be the sum of all values of points, assume we can divide this tree to k k k partitions, then the s u b s u m subsum subsum of each partition equals to s u m / k sum / k sum/k, this implies that k ∣ s u m k | sum ksum

The range of k k k is [ 1 , N ] [1, N] [1,N] satisfying k ∣ s u m k | sum ksum simultaneously, so all valid values of k k k is the factors of s u m sum sum, and less than or equal to N N N. O ( s q r t ( s u m ) ) = 1000 O( sqrt(sum)) = 1000 O(sqrt(sum))=1000.

Now, the question is, given a k k k, check if it is workable which is equivalent to whether would divide this tree to partitions with the same value s u m / k sum / k sum/k (emitting whether the number of partitions equals to k k k, due to it’s implied).

So, given a s u b s u m = s u m / k subsum = sum / k subsum=sum/k, if we can divide this tree to some partitions that with the same value of s u b s u m subsum subsum.
Suppose these partitions are T 1 , T 2 , . . . , T k T_1, T_2, ..., T_k T1,T2,...,Tk, for a partition T i T_i Ti, suppose x x x is a point within it, this partition T i T_i Ti may contains some parent-nodes of x x x partially, and also contains some son-nodes of x x x partially.
On other words, T i T_i Ti may be not a simple-path, it may have several endpoints. So, T i T_i Ti can not be recorded when processing the DFS. This is the pivot for solving this problem.

The importance is, there must exists a T i T_i Ti that is a sub-tree, while a sub-tree can be recorded within a DFS (sub-tree is composed of one root-points and its all son-points).

Let the initial tree is T r Tr Tr, when we get the T i T_i Ti (which is a sub-tree for T r Tr Tr), then we remove it from T r Tr Tr, then the new tree becomes T r 1 Tr1 Tr1, it has k − 1 k-1 k1 partitions.
This rule also effects in T r 1 Tr1 Tr1, that there also exists a T j T_j Tj that is a sub-tree for T r 1 Tr1 Tr1 (not for T r Tr Tr).

The detail algorithm is, when we are doing DFS, for the current point C C C, get it value s s s of this sub-tree (the value of C C C plus all the DFS-return of its son-points), if equals to s u b s u m subsum subsum, then remove this sub-tree, return 0 0 0 to DFS-return; otherwise, it must connect to his parent, so return s s s.

Code

//{ Graph-Build
static constexpr int Graph_point_count_ = 20005, Graph_edge_count_ = 40005;
int Graph_head[ Graph_point_count_], Graph_ver[ Graph_edge_count_], Graph_nex[ Graph_edge_count_];
int Graph_edge_index;
inline void Graph_init(){
    memset( Graph_head, -1, sizeof( Graph_head));
    Graph_edge_index = 0;
}
inline void Graph_addEdge( int _from, int _to){
    // Graph_wth[ Graph_edge_index] = _wth;
    Graph_ver[ Graph_edge_index] = _to;
    Graph_nex[ Graph_edge_index] = Graph_head[ _from];
    Graph_head[ _from] = Graph_edge_index ++;
}
//} Graph-Build
class Solution {
public:
    vector< int> A;
    int Sub;
    int Dfs( int _cur, int _fa){
        int sum = A[ _cur];
        for( int j, i = Graph_head[ _cur]; ~i; i = Graph_nex[ i]){
            j = Graph_ver[ i];
            if( j == _fa){ continue;}
            sum += Dfs( j, _cur);
        }
        if( sum == Sub){ return 0;}
        return sum;
    }
    bool Check( int _s){
        Sub = _s;
        return Dfs( 0, -1) == 0;
    }
    int componentValue(vector<int>& AA, vector<vector<int>>& E) {
        A = AA;
        Graph_init( );
        for( auto & i : E){
            Graph_addEdge( i[0], i[1]);
            Graph_addEdge( i[1], i[0]);
        }
        int ma = *max_element( A.begin(), A.end());
        int sum = accumulate( A.begin(), A.end(), 0);
        int ans = 0;
        for( int cont = min( int( A.size()), sum / ma); ; --cont){
            if( sum % cont == 0){
                if( Check( sum / cont)){
                    return cont - 1;
                }
            }
        }
        assert( 0);
        return 0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值