zoukankan      html  css  js  c++  java
  • 「题解」GYM 101620J Justified Jungle

    (t=k+1),枚举 (t),最多只有 (d(n)) 个,随便钦点一个为根,每个子树的大小都是 (c=frac{n}{t}),易得充要条件为 (size)(c) 倍数的树的个数 (geq t)

    (Rightarrow):对于所有分出来的连通块,其 (dep) 最小的节点 (size) 一定是 (c) 的倍数,所以 (size)(c) 倍数的树的个数 (geq t)

    (Leftarrow):构造,对于每次把 (size=c) 的子树删除,然后更新其它点的 (size).这种构造是始终存在的,即不会出现树未删完并且不存在这样的子树的情况。证明考虑同样的删法,每次把子树中不存在 (size)(c) 的倍数且自己的 (size)(c) 的倍数的子树删掉,删的总次数一定 (<t),与假设矛盾。

    实现上采用狄里克雷后缀和,时间复杂度可以到 (mathcal{O}(nlog log n))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define pb emplace_back
    #define mp std::make_pair
    #define fi first
    #define se second
    typedef long long ll;
    typedef std::pair<int, int> pii;
    typedef std::pair<ll, int> pli;
    typedef std::pair<ll, ll> pll;
    typedef std::vector<int> vi;
    typedef std::vector<ll> vll;
    const ll mod = 998244353;
    ll Add(ll x, ll y) { return (x+y>=mod) ? (x+y-mod) : (x+y); }
    ll Mul(ll x, ll y) { return x * y % mod; }
    ll Mod(ll x) { return x < 0 ? (x + mod) : (x >= mod ? (x-mod) : x); }
    ll cadd(ll &x, ll y) { return x = (x+y>=mod) ? (x+y-mod) : (x+y); }
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 1000100;
    int n, a[N], siz[N], p[N], pct;
    bool vis[N];
    void pre() {
    	vis[1] = 1;
    	for(int i = 2; i <= n; ++i) {
    		if(!vis[i]) p[++pct] = i;
    		for(int j = 1; j <= pct && i * p[j] <= n; ++j) {
    			vis[i*p[j]] = 1;
    			if(i%p[j] == 0) break ;
    		}
    	}
    }
    vi eg[N];
    void dfs(int x, int f) {
    	siz[x] = 1;
    	for(auto v : eg[x])
    		if(v != f) {
    			dfs(v, x);
    			siz[x] += siz[v];
    		}
    	a[siz[x]]++;
    }
    signed main() {
    	read(n); pre();
    	for(int i = 1; i < n; ++i) {
    		int x, y; read(x); read(y);
    		eg[x].pb(y); eg[y].pb(x);
    	}
    	dfs(1, 0);
    	for(int i = 1; i <= pct; ++i)
    		for(int j = n/p[i]; j; --j)
    			a[j] += a[j*p[i]];
    	vi ans;
    	for(int i = 2; i <= n; ++i)
    		if(n % i == 0 && a[n/i] >= i)
    			printf("%d ", i-1);
    	return 0;
    }
    
  • 相关阅读:
    Linux下c开发 之 线程通信(转)
    mount -t nfs 的使用
    window共享linux下的文件 samba
    C/C++ 的使用
    php获取格式时间和时间戳
    php压缩文件夹
    php递归删除文件夹
    php生成文件夹(递归生成)
    QQ音乐API分析记录
    $(this)与this的区别
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15398715.html
Copyright © 2011-2022 走看看