Region Separation (CF1034C)

Region Separation(CF1034C)


明确题意:

1.每次砍完之后,所有联通快的权值和相等。

2.每次一个边集的边同时断,可以断多次边集。


题解:

和学长馈赠7类似,是加强版。

首先可以想到计算出每个子树的权值和——\(siz\) (以 \(1\) 为根)。

设切到最后每个联通块的权值和为 \(k\) ,那么合法的 \(k\) 满足 \(k|siz_1\)

\(cnt_k=\sum_{i=1}^n{[siz_i \equiv 0 (mod \ k)]}\) ,合法的 \(k\) 就还要满足 \(cnt_k=\frac{siz_1}{k}\)

证明:

\(cnt_k\) 实际上是满足 \(siz_i \equiv 0 (mod \ k)\) 的节点个数。

这些节点要选择断开与父节点相连的边,如果我们没有断开 \(\frac{siz_1}{k}-1\) 条边(考虑到根节点不用断,实际上断开了 \(\frac{siz_1}{k}-1\) 条边),也就没有把这棵树分成 \(\frac{siz_1}{k}\) 个部分,那不可能每个部分的权值和为 \(k\)

\(\text{Q.E.D.}\)

但是还有一个问题:\(k\) 的范围达到了 \(10^6\times 10^9\) ,开桶存完全是不现实的。

于是考虑转变一下 \(cnt\) 的定义。

新定义\(cnt_s\) 为满足最后剩下了 \(s\) 个联通块,要断开与祖先相连的边的点的个数。(可能说不太清楚,看式子吧,实际上是 \(s=\frac{siz_1}{k}\),代换了一下,这样桶存的范围变成了 \(10^6\)

既要满足:

\[cnt_s=\sum_{i=1}^{n}[siz_i \equiv 0(mod \ \frac{siz_1}{s})] ((1<s\le n) \land (s|siz_1)) \]

合法条件是 \(cnt_s=s\)

计算 \(cnt\)

暴力枚举 \(s\)\(i\) 复杂度为 \(O(n^2)\)

发现:对于一颗权值和为 \(siz_i\) 的子树来说,它如果能对 \(s\) 做贡献,要满足:

\[siz_i\equiv 0(mod\ \frac{siz_1}{s})\\ siz_i=t\times \frac{siz_1}{s}\\ s=t\times \frac{siz_1}{siz_i}\\ \]

\(d=\gcd(siz_1,siz_i)\)\(siz_1=a\times d\)\(siz_i=b\times d\) ,则 \(gcd(a,b)=1\)

所以

\[s=t\times \frac{a}{b} \]

发现:当 \(b|t\) 是,\(s\) 才为整数,即对 \(s\) 有贡献,所以 \(s=g\times a(g=\frac{t}{b})\)

得出结论:当 \(\frac{siz_1}{\gcd(siz_1,siz_i)}|s\) 时, \(siz_i\) 会在 \(cnt_s\) 中做贡献。

这里的计算是枚举 \(\frac{siz_1}{\gcd(siz_1,siz_i)}\) 的倍数,调和级数,复杂度 \(O(n \ln n)\)

这只是第一步:判断那些状态合法,接下来还要计算方案数。

\(f_s\) 为最后剩下了 \(s\) 个联通块的方案数。

初始化:\(f_s=[cnt_s = s]\)

考虑转移:\(f_s=\sum_{s|s_1}f_{s_1}\) (切一下成倍增加)。

注意:\(f_1=1\) 需要特殊判一下。

最后这部分时间复杂度 \(O(n \ln n)\)


Code moo~~
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register int
#define pc_ putchar(' ')
#define pc_n putchar('\n')
#define Bessie signed
const int CTR = 1e6 + 7, MOD = 1e9 + 7;
int n;
int a[CTR], fa[CTR], siz[CTR];
int cnt[CTR], f[CTR];
int ans;
int gcd(int x, int y)
{
    return !y ? x : gcd(y, x % y);
}
Bessie main()
{
    n = read();
    for(re i = 1; i <= n; ++i)
        a[i] = read();
    for(re i = 2; i <= n; ++i)
        fa[i] = read();
    for(re i = n; i; --i)
    {
        siz[i] += a[i];
        siz[fa[i]] += siz[i];
    }
    for(re i = 1; i <= n; ++i)
        if(siz[1] / gcd(siz[1], siz[i]) <= n)
            ++cnt[siz[1] / gcd(siz[1], siz[i])];
    for(re i = 1; i <= n; ++i)
        if(cnt[i])
            for(re j = i; j <= n; j += i)
                f[j] += cnt[i];
    for(re i = 1; i <= n; ++i)
        f[i] = (f[i] == i);
    for(re i = n; i > 1; --i)
    {
        if(f[i])
        {
            for(re j = i + i; j <= n; j += i)
                (f[i] += f[j]) %= MOD;
            (ans += f[i]) %= MOD;
        }
    }
    ot(ans + 1),pc_n;
    return 0;
}

\[\bm{hzoi-Creator\_157} \]

posted @ 2022-10-14 21:02  Creator_157  阅读(37)  评论(1编辑  收藏  举报