• 2018-2019 ACM-ICPC, Asia Xuzhou Regional Contest Solution


    A. Rikka with Minimum Spanning Trees

    题意:

    给出一个图,求最小生成树的个数和权值

    思路:

    因为数据随机,只有一个MST

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ull unsigned long long
     5 ull k1, k2;
     6 const ull MOD = (ull)1e9 + 7;
     7 int t, n, m;
     8 
     9 ull f()
    10 {
    11     ull k3 = k1, k4 = k2;
    12     k1 = k4;
    13     k3 ^= k3 << 23;
    14     k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    15     return k2 + k4;
    16 }
    17 
    18 struct Edge
    19 {
    20     int u, v; ull w;
    21     Edge() {}
    22     Edge(int u, int v, ull w) : u(u), v(v), w(w) {}
    23     bool operator < (const Edge &other) const { return w < other.w; }
    24 }edge[100010];
    25 
    26 int fa[100010];
    27 int find(int x) { return fa[x] == 0 ? x : fa[x] = find(fa[x]); } 
    28 
    29 void Kruskal()
    30 {
    31     memset(fa, 0, sizeof fa);
    32     sort(edge + 1, edge + 1 + m);
    33     int cnt = 1;
    34     ull res = 0;
    35     for (int i = 1; i <= m; ++i)
    36     {
    37         int u = edge[i].u, v = edge[i].v; ull w = edge[i].w; 
    38 //        cout << i << " " << w << endl;
    39         int fu = find(u), fv = find(v);
    40         if (fu == fv) continue;
    41         ++cnt;
    42         res = (res + w) % MOD;
    43         fa[fu] = fv;
    44         if (cnt == n) break;  
    45     }    
    46     if (cnt != n) res = 0;
    47     printf("%llu
    ", res);  
    48 }
    49 
    50 int main()
    51 {
    52     scanf("%d", &t);
    53     while (t--)
    54     {
    55         scanf("%d%d%llu%llu", &n, &m, &k1, &k2);
    56         for (int i = 1; i <= m; ++i)
    57         {
    58             edge[i].u = f() % n + 1;
    59             edge[i].v = f() % n + 1;
    60             edge[i].w = f();
    61 //            cout << edge[i].u << " " << edge[i].v << " " << edge[i].w << endl;
    62         }
    63         Kruskal();     
    64     }    
    65     return 0;
    66 }
    View Code

    G. Rikka with Intersections of Paths

    题意:

    给出一棵树,以及$m条简单路径,求从这些简单路径中选出k条,有多少种不同方式使得路径交至少为1$

    思路:

    枚举路径交的$LCA$, 对于一个点来说,它的贡献是,所有经过它的路径假设为$x$

    那么有$C_x^k$ 但是对于一些路径的$LCA不是它,那么这些路径中选出k条的贡献肯定在他们所在的LCA处被计算$

    所以应该被减去,也就是说假设经过它但是$LCA不是它的路径条数假设为y条$

    那么需要减去$C_y^k$

    最终贡献为$C_x^k - C_y^k$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define ll long long
      5 #define N 300010
      6 const ll MOD = (ll)1e9 + 7;
      7 int t, n, m, k;
      8 vector <int> G[N];
      9 
     10 int fa[N], deep[N], sze[N], son[N], top[N];
     11 void DFS(int u)
     12 {
     13     sze[u] = 1;
     14     for (auto v : G[u]) if (v != fa[u])
     15     {
     16         fa[v] = u;
     17         deep[v] = deep[u] + 1;
     18         DFS(v);
     19         sze[u] += sze[v];
     20         if (!son[u] || sze[v] > sze[son[u]]) son[u] = v;
     21     }
     22 }
     23 
     24 void getpos(int u, int sp)
     25 {
     26     top[u] = sp;
     27     if (!son[u]) return;
     28     getpos(son[u], sp);
     29     for (auto v : G[u]) if (v != fa[u] && v != son[u])
     30         getpos(v, v);
     31 }
     32 
     33 int querylca(int u, int v)
     34 {
     35     while (top[u] != top[v])
     36     {
     37         if (deep[top[u]] < deep[top[v]]) swap(u, v); 
     38         u = fa[top[u]];
     39     }
     40     return deep[u] > deep[v] ? v : u;
     41 }
     42 
     43 int cnt[N], tag[N];
     44 void add(int u)
     45 {
     46     for (auto v : G[u]) if (v != fa[u])
     47     {
     48         add(v);
     49         cnt[u] += cnt[v]; 
     50     }
     51 }
     52 
     53 ll fac[N], inv[N];
     54 ll qmod(ll base, ll n)
     55 {
     56     ll res = 1;
     57     while (n)
     58     {
     59         if (n & 1) res = (res * base) % MOD;
     60         base = (base * base) % MOD;
     61         n >>= 1;
     62     }
     63     return res;
     64 }
     65 
     66 void init()
     67 {
     68     fac[0] = 1;
     69     for (int i = 1; i <= 300000; ++i) fac[i] = (fac[i - 1] * i) % MOD;
     70     inv[300000] = qmod(fac[300000], MOD - 2);
     71     for (int i = 300000; i >= 1; --i) inv[i - 1] = (inv[i] * i) % MOD;
     72 }
     73 
     74 ll C(int n, int m)
     75 {
     76     if (m > n) return 0;
     77     return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
     78 }
     79 
     80 int main()
     81 {
     82     init();
     83     scanf("%d", &t);
     84     while (t--)
     85     {
     86         scanf("%d%d%d", &n, &m, &k);
     87         for (int i = 1; i <= n; ++i) G[i].clear(), son[i] = 0, cnt[i] = 0, tag[i] = 0;
     88         for (int i = 1, u, v; i <= n - 1; ++i)
     89         {
     90             scanf("%d%d", &u, &v);
     91             G[u].push_back(v);
     92             G[v].push_back(u);
     93         }
     94         DFS(1); getpos(1, 1);
     95         for (int i = 1, u, v; i <= m; ++i)
     96         {
     97             scanf("%d%d", &u, &v);
     98             int lca = querylca(u, v);
     99             ++tag[lca];
    100             ++cnt[u];
    101             ++cnt[v];
    102             --cnt[lca];
    103             if (fa[lca]) --cnt[fa[lca]];
    104         }
    105         add(1);
    106         ll res = 0;
    107         for (int i = 1; i <= n; ++i) res = (res + C(cnt[i], k) - C(cnt[i] - tag[i], k) + MOD) % MOD;
    108         printf("%lld
    ", res);
    109     }
    110     return 0;
    111 }
    View Code
  • 相关阅读:
    oracle 判断字符串是否包含指定内容
    java 如何使用多线程调用类的静态方法?
    oracle 快速复制表结构、表数据
    oracle 清空表数据的2种方式及速度比较
    一、Instrument之Core Animation工具
    net登录积分(每天登录积分仅仅能加一次) 时间的比較
    正规方程 Normal Equation
    笑谈贝叶斯网络(干货)上
    SQL SERVER 面试题
    好的创始人想要改变世界,最好的创始人还要不放弃——扎克伯格清华中文演讲
  • 原文地址:https://www.cnblogs.com/Dup4/p/10133077.html
Copyright © 2020-2023  润新知