• [组合计数]Counting Stickmen 2022杭电多校第7场 1003


    Problem Description

    Namesolo has fallen in love with the game Stick Fight. But when he is playing the game, he wonders how to find out the number of stickmen in the game.

    In this question, we define the stick man as shown in the picture above. It has a chain of length 11 as the head, two chains of length 22 as the arms, a chain of length 11 as the body, and two chains of length 11 as the legs. For example, the red part in this picture can be viewed as a stick man, with chain (2,3)(2,3) to be the head, chains (3,4,6)(3,4,6) and (3,9,10)(3,9,10) to be the arms, chain (3,5)(3,5) to be the body, and chains (5,7)(5,7) and (5,8)(5,8) to be the legs.

    The game can be viewed as a tree, and Namesolo wants to know how many stickmen are there. Please note that two stickmen are different when there is at least one different edge between the two edge sets that make up the two stickmen.

    Because the answer may be too large, Namesolo wants to know the answer modulo 998244353998244353.

    Input

    The first line of input contains one integer T\ (1\le T\le 15)T (1≤T≤15), indicating the number of test cases.

    For each test case, the first line contains an integer nn (1\le n \le 5\times 10^51≤n≤5×105), indicating the number of vertices in the tree. Each of the following n-1n−1 lines contains two integers a,ba,b (1 \le a,b \le n1≤a,b≤n), indicating that there is an edge connecting aa and bb in the tree.

    It is guaranteed that the sum of nn over all cases won't exceed 3 \times 10^63×106.

    Output

    For each test case, output an integer representing the answer modulo 998244353998244353.

    Sample Input

    1

    9

    1 2

    2 3

    3 4

    2 5

    5 6

    2 7

    7 8

    7 9

    Sample Output

    1

    题意: 给出一棵树的结构,问这棵树中存在几个火柴人,火柴人的结构如上图中红色标示。

    分析: 可以枚举火柴人的躯干,也就是图中点3到点5的那条边,设x为靠近头的端点,y为靠近腿的端点,腿的方案数就是一个组合数,从y的度数-1中挑2个点,手的方案数稍复杂一些,首先要求出到x点距离为2的点个数,这个值就是x相邻点的度数-1然后加和,然后还需要剔除在腿上的点,也就是再减掉y的度数-1个点,从这些点中选取2个点作为两只手,不过要注意还得减去两只手来自同一只手臂的情况,然后就剩下头的方案数了,这个比较容易得到,只需要在x相邻点中剔除两手臂和腿这三点,也就是x度数-3。最后把腿、手和头的方案数乘起来就是答案。

    具体代码如下:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define int long long
    9. #define pii pair
    10. using namespace std;
    11. vector<int> tr[500005];
    12. pii e[500005];
    13. int a[500005];//ai记录第i点周围点的度数-1之和
    14. int b[500005];//bi记录第i点周围点C(度数-1,2)之和
    15. const int mod = 998244353;
    16. int ksm(int base, int power){
    17. int ans = 1;
    18. while(power){
    19. if(power&1) ans = ans*base%mod;
    20. base = base*base%mod;
    21. power >>= 1;
    22. }
    23. return ans;
    24. }
    25. int C(int x){//返回C(x, 2)
    26. if(x < 2) return 0;
    27. return x*(x-1)%mod*ksm(2, mod-2)%mod;
    28. }
    29. signed main()
    30. {
    31. int T;
    32. cin >> T;
    33. while(T--){
    34. int n;
    35. cin >> n;
    36. for(int i = 1; i <= n; i++){
    37. tr[i].clear();
    38. a[i] = b[i] = 0;
    39. }
    40. for(int i = 1; i < n; i++){
    41. scanf("%lld%lld", &e[i].first, &e[i].second);
    42. tr[e[i].first].push_back(e[i].second);
    43. tr[e[i].second].push_back(e[i].first);
    44. }
    45. //预处理
    46. for(int i = 1; i <= n; i++){
    47. for(int j = 0; j < tr[i].size(); j++){
    48. int to = tr[i][j];
    49. a[i] = (a[i]+tr[to].size()-1)%mod;
    50. b[i] = (b[i]+C(tr[to].size()-1))%mod;
    51. }
    52. }
    53. int ans = 0;
    54. for(int i = 1; i < n; i++){//枚举每条边
    55. int x = e[i].first;
    56. int y = e[i].second;
    57. int leg = C(tr[y].size()-1);//腿的方案数
    58. int hand = C(((a[x]-(tr[y].size()-1))%mod+mod)%mod);//手的方案数
    59. hand = ((hand-(b[x]-C(tr[y].size()-1)))%mod+mod)%mod;
    60. int head = tr[x].size()-3;//头的方案数
    61. if(head < 0) head = 0;
    62. ans = (ans+leg*hand%mod*head%mod)%mod;
    63. //另一个方向的边
    64. swap(x, y);
    65. leg = C(tr[y].size()-1);//腿的方案数
    66. hand = C(((a[x]-(tr[y].size()-1))%mod+mod)%mod);//手的方案数
    67. hand = ((hand-(b[x]-C(tr[y].size()-1)))%mod+mod)%mod;
    68. head = tr[x].size()-3;//头的方案数
    69. if(head < 0) head = 0;
    70. ans = (ans+leg*hand%mod*head%mod)%mod;
    71. }
    72. cout << ans << endl;
    73. }
    74. return 0;
    75. }

  • 相关阅读:
    Python SQLAlchemy ORM的with_entities方法了解和简单使用
    [DDC]Deep Domain Confusion: Maximizing for Domain Invariance
    [推公式]Shinobu loves trip 2022杭电多校第6场 1007
    MySQL 本地安装
    白炽灯和节能灯哪个更护眼?分享几款护眼的LED灯
    尝试使用java写redis分布式锁
    手摸手系列之EasyPoi导出Excel横向遍历实战
    【题解】P8579 [CoE R5/Stoi2029] 半岛铁盒
    5G注册流程详解
    Google play的企业开发者账号比个人号上包成功率更高?
  • 原文地址:https://blog.csdn.net/m0_55982600/article/details/126269981