zoukankan      html  css  js  c++  java
  • CF1034C Region Separation【分析性质,dp】

    题目描述:你有一棵 (n) 个节点的树,点带权,每次可以砍掉一些边,使得每个联通块的权值和相等,求砍树方案数。

    数据范围:(nle 10^6,a_ile 10^9)

    (s_x=sum_{i在x子树内} a_i)(S=s_{rt})

    首先假设只有一次操作,要分割成 (k) 部分,那么要么无解要么方案唯一。

    按子树权值和从小到大考虑,如果当前子树权值和 (<frac{S}{k}) 则不分割,(=frac{S}{k}) 就要分割,否则无解。

    还有一种考虑的方法,我们只能割掉 (frac{S}{k}|s_x)(x) 与其父亲的边,设 (f_k=sum_x[frac{S}{k}|s_x]),则 (f_kle k)。所以有解当且仅当 (f_k=k)为什么我猜到这个结论还以为是错的啊...

    如何求出 (f_k) 呢,则若 (frac{S}{k}|s_i) 时,(s_i)(k) 造成贡献,也就是 (frac{S}{k}|gcd(s_i,S)),即 (frac{S}{gcd(s_i,S)}|k)。所以只需要枚举倍数即可。

    设最后一次剖分为 (k) 份时的答案为 (dp_k),则

    [dp_k=[f_k=k]sum_{t|k}dp_t ]

    总时间复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    #define Rint register int
    #define MP make_pair
    #define PB push_back
    #define fi first
    #define se second
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pii;
    const int N = 1000003, mod = 1e9 + 7;
    inline int ksm(int a, int b){
    	int res = 1;
    	for(;b;b >>= 1, a = (LL) a * a % mod) if(b & 1) res = (LL) res * a % mod;
    	return res;
    }
    template<typename T>
    inline void read(T &x){
    	int ch = getchar(); x = 0; bool f = false;
    	for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
    	if(f) x = -x;
    }
    template<typename T>
    inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    template<typename T>
    inline bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    LL gcd(LL a, LL b){return b ? gcd(b, a % b) : a;}
    inline void qmo(int &x){x += (x >> 31) & mod;}
    int n, fa[N], f[N], dp[N], ans;
    LL s[N];
    int main(){
    	read(n);
    	for(Rint i = 1;i <= n;++ i) read(s[i]);
    	for(Rint i = 2;i <= n;++ i) read(fa[i]);
    	for(Rint i = n;i >= 2;-- i) s[fa[i]] += s[i];
    	for(Rint i = 1;i <= n;++ i){
    		LL x = s[1] / gcd(s[1], s[i]);
    		if(x <= n) ++ f[x];
    	}
    	for(Rint i = n;i;-- i) if(f[i])
    		for(Rint j = i << 1;j <= n;j += i) f[j] += f[i];
    	dp[1] = 1;
    	for(Rint i = 1;i <= n;++ i) if(f[i] == i){
    		for(Rint j = i << 1;j <= n;j += i) qmo(dp[j] += dp[i] - mod);
    		qmo(ans += dp[i] - mod);
    	}
    	printf("%d
    ", ans);
    }
    
  • 相关阅读:
    生成器
    ELK出现unassigned_shards解决办法
    ElK集群 采集 redis 数据
    postgresql-12编译安装
    openshift 3.11安装部署
    Linux TCP漏洞 CVE-2019-11477 CentOS7 修复方法
    zabbix-server安装部署配置
    zabbix-proxy安装部署
    harbor镜像仓库-02-https访问配置
    harbor镜像仓库-01-搭建部署
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/13136782.html
Copyright © 2011-2022 走看看