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;
    }
    
  • 相关阅读:
    String类的intern()方法,随常量池发生的变化
    JDK8的JVM内存结构,元空间替代永久代成为方法区及常量池的变化
    wait()、notify()方法原理,以及使用注意事项--丢失唤醒、虚假唤醒
    消费者、生产者Java代码示例,wait-notify实现
    volatile、Synchronized实现变量可见性的原理,volatile使用注意事项
    CAS及其ABA问题
    JUC包Lock机制的支持--AQS
    JUC包实现的同步机制,原理以及简单用法总结
    Synchronized机制下偏向锁、轻量级锁、重量级锁的适用场景
    临时表循环插入
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15398715.html
Copyright © 2011-2022 走看看