Codeforces Round #735 (Div. 2) E. You

  • Post author:
  • Post category:其他




题意



T

组测试样例,每组测试样例:

给你一棵

n

个节点的树,你要进行

n

次删除,每次删除选择树上一个没有删过的节点,将它删除,删除后会得到分数,分数等于与它连接并且没有被删除的节点个数。

例如如图所示的这样一棵树:

在这里插入图片描述

删除节点的顺序为

[2, 3, 1]

,那么分数分别是

[1, 1, 0]

,所以

[1, 2, 3]

点分别的分数就是

[0, 1, 1]



我们称

[0, 1, 1]

是一种分数排列



你可以改变删除节点的顺序,让你分别输出分数

gcd(题目规定:gcd 0 不变)= [1, n]

的分数排列有多少种情况,答案

mod 998244353

数据范围:

1 <= T <= 10000, 2 <= n <= 1e5, T组数据 n 的和不超过 3e5.



思路


定义

f(g)

等于

gcd = g, 2g, 3g, 4g...kg <= n

的分数排列种数的和。


我们先分别求出

f(1), f(2) ... f(n)

,然后再对其进行容斥,就能得到

gcd(1), gcd(2) ... gcd(n)

的分数排列种数。

  • 对于连接

    u, v

    这条边,它只会影响

    u, v

    的分数,所以每增加一条边都会让

    排列种数 * 2

    ,可以得到




    f

    (

    1

    )

    =

    2

    (

    n

    1

    )

    f(1) = 2^{(n-1)}






    f


    (


    1


    )




    =









    2











    (


    n





    1


    )














  • f(g),g = [2, n]

    的分数排列种数只可能是 0 或者 1。

    • 我们尝试构造

      g = k

      的分数排列,我们从叶子节点往上进行分析。
    • 对于

      叶子节点

      leaf


      肯定不能删,因为删了就会存在分数 1,这样

      gcd

      就肯定不可能等于

      k

      了,我们只能选择删

      leaf

      的父亲。
    • 这时候我们关注

      leaf



      父亲

      f


      ,在不考虑

      f 的父亲

      的情况,删除

      f

      得到的分数如果不能整除

      k

      ,那就把

      f 的父亲

      考虑进来,如果还是不能整除

      k



      gcd

      就肯定不可能等于

      k

      了。如果能整除

      k



      f



      f 的父亲

      的边贡献给了谁也就知道了。
    • 按照上面的思路,我们会发现分数排列只可能有一种情况。
  • 如果

    i-1

    不能整除

    g

    ,是肯定不会存在一个分数排列

    gcd = g

    的倍数的。



代码

#include<iostream>
#include<vector>
using namespace std;
const int N = 1e5+5;
const int MOD = 998244353;
vector<int> map_[N];
int f[N], a[N];

bool has_ans;
void dfs(int u, int f, int k) {
    for(int i = 0; i < map_[u].size(); i++) {
        if(!has_ans) return;
        int to = map_[u][i];
        if(to == f) continue;
        dfs(to, u, k);
        if(a[to]%k) {
            a[to]++;
            if(a[to]%k) has_ans = false;
        } else {
            a[u]++; // 当 u == 1 的时候,++ 后一定 % k == 0
        }
    }
}

int main(void) {
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while(T--) {
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++) {
            map_[i].clear();
            f[i] = 0;
        }
        f[1] = 1;
        for(int i = 1; i < n; i++) {
            f[1] *= 2, f[1]%=MOD;
        }
        for(int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            map_[u].push_back(v);
            map_[v].push_back(u);
        }
        for(int i = 2; i <= n; i++) {
            if((n-1)%i != 0) continue;

            for(int j = 1; j <= n; j++) a[j] = 0;

            has_ans = true;
            dfs(1, 0, i);
            f[i] = has_ans;
        }

        for(int i = n; i >= 1; i--) {
            for(int j = i+i; j <= n; j += i) {
                f[i] = (f[i] - f[j] + MOD) % MOD;
            }
        }

        for(int i = 1; i <= n; i++) {
            cout << f[i];
            if(i == n) cout << '\n';
            else cout << ' ';
        }
    }

    return 0;
}



版权声明:本文为bbbbswbq原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。