2020 Multi-University Training Contest 6


Road To The 3rd Building · 期望

http://acm.hdu.edu.cn/showprobem.php?pid=6827
期望 = 区间的权值 * 区间出现的次数

n = 3 n=3 n=3

E ( x ) = ∑ x × p ( x ) = a 1 + 1 2 ( a 1 + a 2 ) + 1 3 ( a 1 + a 2 + a 3 ) + a 2 + 1 2 ( a 2 + a 3 ) + a 3 n ( n + 1 ) 2 E(x)=\sum x\times p(x)=\cfrac{ a_1+\frac{1}{2}(a_1+a_2)+\frac{1}{3}(a_1+a_2+a_3)+a_2+\frac{1}{2}(a_2+a_3)+a_3}{\cfrac{n(n+1)}{2}} E(x)=x×p(x)=2n(n+1)a1+21(a1+a2)+31(a1+a2+a3)+a2+21(a2+a3)+a3

= a 1 ( 1 + 1 2 + 1 3 ) + a 2 ( 1 + 2 1 2 + 1 3 ) + a 3 ( 1 + 1 2 + 1 3 ) 6 =\cfrac{a_1(1+\frac{1}{2}+\frac{1}{3})+a_2(1+2\frac{1}{2}+\frac{1}{3})+a_3(1+\frac{1}{2}+\frac{1}{3})}{6} =6a1(1+21+31)+a2(1+221+31)+a3(1+21+31)

n = 4 n=4 n=4

E ( x ) = a 1 + 1 2 ( a 1 + a 2 ) + 1 3 ( a 1 + a 2 + a 3 ) + 1 4 ( a 1 + a 2 + a 3 + a 4 ) + a 2 + 1 2 ( a 2 + a 3 ) + 1 3 ( a 2 + a 3 + a 4 ) + a 3 + 1 2 ( a 3 + a 4 ) + a 4 10 E(x)=\cfrac{ a_1+\frac{1}{2}(a_1+a_2)+\frac{1}{3}(a_1+a_2+a_3)+\frac{1}{4}(a_1+a_2+a_3+a_4)+a_2+\frac{1}{2}(a_2+a_3)+\frac{1}{3}(a_2+a_3+a_4)+a_3+\frac{1}{2}(a_3+a_4)+a_4}{10} E(x)=10a1+21(a1+a2)+31(a1+a2+a3)+41(a1+a2+a3+a4)+a2+21(a2+a3)+31(a2+a3+a4)+a3+21(a3+a4)+a4

= a 1 ( 1 + 1 2 + 1 3 + 1 4 ) + a 2 ( 1 + 2 1 2 + 2 1 3 + 1 4 ) + a 3 ( 1 + 2 1 2 + 2 1 3 + 1 4 ) + a 4 ( 1 + 1 2 + 1 3 + 1 4 ) 10 =\cfrac{a_1(1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4})+a_2(1+2\frac{1}{2}+2\frac{1}{3}+\frac{1}{4})+a_3(1+2\frac{1}{2}+2\frac{1}{3}+\frac{1}{4})+a_4(1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4})}{10} =10a1(1+21+31+41)+a2(1+221+231+41)+a3(1+221+231+41)+a4(1+21+31+41)

以此类推,当 n = 5 n=5 n=5

E ( x ) = a 1 ( 1 + 1 2 + 1 3 + 1 4 + 1 5 ) + a 2 ( 1 + 2 1 2 + 2 1 3 + 2 1 4 + 1 5 ) + a 3 ( 1 + 2 1 2 + 3 1 3 + 2 1 4 + 1 5 ) + a 4 ( 1 + 2 1 2 + 2 1 3 + 2 1 4 + 1 5 ) + a 5 ( 1 + 1 2 + 1 3 + 1 4 + 1 5 ) 15 E(x)=\cfrac{a_1(1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4}+\frac{1}{5})+a_2(1+2\frac{1}{2}+2\frac{1}{3}+2\frac{1}{4}+\frac{1}{5})+a_3(1+2\frac{1}{2}+3\frac{1}{3}+2\frac{1}{4}+\frac{1}{5})+a_4(1+2\frac{1}{2}+2\frac{1}{3}+2\frac{1}{4}+\frac{1}{5}) +a_5(1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4}+\frac{1}{5})}{15} E(x)=15a1(1+21+31+41+51)+a2(1+221+231+241+51)+a3(1+221+331+241+51)+a4(1+221+231+241+51)+a5(1+21+31+41+51)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 1e6 + 10;
ll n;

ll qpow(ll a, ll b) {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}


ll Add(ll x, ll y) {
    return (x + y) % mod;
}

ll Sub(ll x, ll y) {
    return (x - y + mod) % mod;
}

ll Mul(ll x, ll y) {
    return (x * y) % mod;
}

ll demo[N], sum[N], a[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    for (int i = 1; i <= 200010; i++) {
        demo[i] = qpow(i, mod - 2); // 1/i
        sum[i] = Add(sum[i - 1], demo[i]); // ∑1/i
    }

    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }

        ll tmp = 0;
        ll res = 0;
        for (int i = 1, j = n; i <= j; i++, j--) {
            // tmp+= sum[j]-sum[i-1]
            tmp = Add(tmp, Sub(sum[j], sum[i - 1]));

            // res+=a[i] * tmp + a[n - i + 1] * tmp;
            res = Add(res, Mul(a[i], tmp));
            if (j > i) {
                res = Add(res, Mul(a[j], tmp));
            }
        }

        ll Inv = qpow(n * (n + 1) / 2, mod - 2); // 1/区间个数
        res = Mul(res, Inv);
        cout << res << endl;
    }
    return 0;
}

Little Rabbit’s Equation · 模拟

http://acm.hdu.edu.cn/showproblem.php?pid=6828

#include <bits/stdc++.h>
using namespace std;
#define between(x, a, b) (a<=x && x<=b)
typedef long long ll;
int bit[20];
string num1, num2, num3;

ll toInt(string s, int b) {
    int sz = s.length();
    for (int i = 0; i < sz; i++) {
        bit[i] = (between(s[i], '0', '9') ? s[i] - '0' : s[i] - 'A' + 10);
    }

    ll res = 0;
    for (int i = 0; i < sz; i++) {
        if (bit[i] >= b) return -1; // 判断数字是否合法
        res = res * b + bit[i];
    }
    return res;
}

bool solve(ll a, ll b, ll c, int op) {
    if (op == 1) return (a + b) == c;
    else if (op == 2) return (a - b) == c;
    else if (op == 3) return (a * b) == c;
    else return ((a % b) == 0 && (a / b == c)); // 防整除精度问题
}

bool check(int b, int op) {
    ll x = toInt(num1, b);
    if (x == -1) return false;
    
    ll y = toInt(num2, b);
    if (y == -1) return false;
    
    ll z = toInt(num3, b);
    if (z == -1) return false;
    
    return solve(x, y, z, op);
}

string s;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    while (cin >> s) {
        int sz = s.length();
        int i = 0, j, op;

        while (i < sz && (between(s[i], '0', '9') || between(s[i], 'A', 'F'))) i++;
        num1 = s.substr(0, i);

        if (s[i] == '+') op = 1;
        else if (s[i] == '-') op = 2;
        else if (s[i] == '*') op = 3;
        else if (s[i] == '/') op = 4;

        i++;
        j = i;
        while (i < sz && (between(s[i], '0', '9') || between(s[i], 'A', 'F'))) i++;
        num2 = s.substr(j, i - j);

        i++;
        j = i;
        while (i < sz && (between(s[i], '0', '9') || between(s[i], 'A', 'F'))) i++;
        num3 = s.substr(j, i - j);

        int f = -1;
        for (int i = 2; i <= 16; i++) {
            if (check(i, op)) {
                f = i;
                break;
            }
        }
        cout << f << endl;
    }
    return 0;
}

Borrow
Asteroid in Love

Fragrant numbers · dp

http://acm.hdu.edu.cn/showproblem.php?pid=6831
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
int n;
int res[N];
string s = " 114514191911451419191145141919";
set<int> f[20][20];

void dfs(int l, int r) {
    if (r - l + 1 <= 4) {
        int num = 0;
        for (int i = l; i <= r; i++) {
            num = num * 10 + (s[i] - '0');
        }
        f[l][r].insert(num);
    }

    for (int i = l; i < r; i++) {
        dfs(l, i);
        dfs(i + 1, r);

        for (int a: f[l][i]) {
            for (int b: f[i + 1][r]) {
                if (a + b <= 5000) {
                    f[l][r].insert(a + b);
                }
                if (a * b <= 5000) {
                    f[l][r].insert(a * b);
                }
            }
        }
    }
}

void init() {
    dfs(1, 13);
    memset(res, INF, sizeof res);
    for (int i = 1; i <= 13; i++) {
        for (int x:f[1][i]) {
            res[x] = min(res[x], i);
        }
    }
    for (int i = 1; i <= 5000; i++) {
        if (res[i] == INF) res[i] = -1;
    }

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    init();
    int T;
    cin >> T;
    for (int cs = 1; cs <= T; cs++) {
        cin >> n;
        cout << res[n] << endl;
    }
    return 0;
}

A Very Easy Graph Problem · 树上任意两点间距离

http://acm.hdu.edu.cn/showproblem.php?pid=6832
官方题解
在这里插入图片描述
树上任意两点间距离的改版

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 1e6 + 10;

struct Edge {
    int v;
    ll w;
};
vector<Edge> e[N];

int a[N];
int n, m;
int fa[N];

int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void Union(int x, int y, ll w) {
    int fx = find(x);
    int fy = find(y);
    if (fx == fy) return;

    e[x].push_back({y, w});
    e[y].push_back({x, w});

    if (fx < fy) {
        fa[fy] = fx;
    } else {
        fa[fx] = fy;
    }
}

ll Mul(ll x, ll y) {
    return (x * y) % mod;
}

ll Add(ll x, ll y) {
    return (x + y) % mod;
}

ll Sub(ll x, ll y) {
    return (x - y + mod) % mod;
}

ll res;
ll sum[N][2];

void dfs1(int u, int f) {
    sum[u][0] = sum[u][1] = 0;

    for (int i = 0, sz = e[u].size(); i < sz; i++) {
        int v = e[u][i].v;
        if (v != f) {
            dfs1(v, u);
            sum[u][0] += sum[v][0];
            sum[u][1] += sum[v][1];
        }
    }
    sum[u][a[u]]++;
}

void dfs2(int u, int f) {
    for (int i = 0, sz = e[u].size(); i < sz; i++) {
        int v = e[u][i].v;
        if (v != f) {
            dfs2(v, u);

            res = Add(res, Mul(e[u][i].w, Mul(sum[v][0], Sub(sum[1][1], sum[v][1]))));
            res = Add(res, Mul(e[u][i].w, Mul(sum[v][1], Sub(sum[1][0], sum[v][0]))));
        }
    }
}

ll p[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    p[0] = 1;
    for (int i = 1; i <= 200010; i++) {
        p[i] = Mul(p[i - 1], 2);
    }

    int T, u, v;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];

            // init
            e[i].clear();
            fa[i] = i;
        }

        for (int i = 1; i <= m; i++) {
            cin >> u >> v;
            Union(u, v, p[i]);
        }
        
        res = 0;
        dfs1(1, 0);
        dfs2(1, 0);

        cout << res << endl;
    }
    return 0;
}

A Very Easy Math Problem
Yukikaze and Smooth numbers


Divisibility

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll b, x;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T;
    cin >> T;
    while (T--) {
        cin >> b >> x;
        if (b % x == 1) {
            cout << "T" << endl;
        } else {
            cout << "F" << endl;
        }
    }
    return 0;
}

Expectation · 矩阵树求生成树个数

http://acm.hdu.edu.cn/showproblem.php?pid=6836

生成树计数问题——矩阵树定理及其证明
矩阵树定理

官方题解
在这里插入图片描述
E ( ∑ i = 0 30 2 i ) = ∑ i = 0 30 E ( 2 i ) = ∑ x × p ( x ) = ∑ i = 0 30 2 i × p ( 2 i ) = ∑ i = 0 30 2 i × 权 值 里 含 有 2 i 的 生 成 树 的 个 数 生 成 树 总 数 E(\sum_{i=0}^{30}2^i)=\sum_{i=0}^{30} E(2^i)=\sum x\times p(x)=\sum_{i=0}^{30} 2^i\times p(2^i)=\sum_{i=0}^{30}2^i\times \cfrac{权值里含有2^i的生成树的个数}{生成树总数} E(i=0302i)=i=030E(2i)=x×p(x)=i=0302i×p(2i)=i=0302i×2i

若要让生成树的权值含有 2 i 2^i 2i ,显然生成树的每一条边的权值都要求含有 2 i 2^i 2i

利用矩阵树定理再求一遍所有含有 2 i 2^i 2i 的边能构造出多少个生成树

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 1e2 + 10;
const int M = 1e5 + 10;
int n, m;

ll res = 0, sum = 0;
int arr[N][N]; // 基尔霍夫矩阵
vector<vector<int>> vec;// n-1阶行列式
struct edge {
    int u, v, w;
} e[M];

ll Mul(ll a, ll b) {
    return (a * b) % mod;
}

ll Add(ll a, ll b) {
    return (a + b) % mod;
}

ll Sub(ll a, ll b) {
    return (a - b + mod) % mod;
}

ll qpow(ll a, ll b) {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1)res = Mul(res, a);
        b >>= 1;
        a = Mul(a, a);
    }
    return res;
}
// 计算行列式的值
ll Determinant(const vector<vector<int>> &A) {
    ll res = 1;
    int n = A.size(), cnt = 0;
    vector<vector<int>> B(n, vector<int>(n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            B[i][j] = A[i][j];
        }
    }

    for (int i = 0; i < n; i++) {
        int pivot = i;
        for (int j = i; j < n; j++) {
            if (abs(B[j][i]) > abs(B[pivot][i])) {
                pivot = j;
            }
        }
        if (i != pivot) {
            swap(B[i], B[pivot]); // 交换两行
            cnt ^= 1;
        }

        if (B[i][i] == 0) return 0;
        ll val = qpow(B[i][i], mod - 2);
        for (int j = i + 1; j < n; j++) {
            ll coe = Mul(B[j][i], val);
            for (int k = i; k < n; k++) {
                B[j][k] = Sub(B[j][k], Mul(coe, B[i][k]));
            }
        }
    }

    for (int i = 0; i < n; i++) {
        res = Mul(res, B[i][i]);
    }
    if (cnt) res = Sub(0, res);
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    for (int cs = 1; cs <= T; cs++) {

        sum = res = 0;
        memset(arr, 0, sizeof arr);
        vec.clear();

        cin >> n >> m;
        for (int i = 1; i <= m; i++) {
            cin >> e[i].u >> e[i].v >> e[i].w;
        }

        for (int i = 1, u, v; i <= m; i++) {
            u = e[i].u;
            v = e[i].v;
            // 构造基尔霍夫矩阵
            arr[u][u]++, arr[v][v]++; // 增加度数
            arr[u][v]--, arr[v][u]--; // 边数取反
        }
		// 取第一个n-1阶行列式
        for (int i = 1; i < n; i++) {
            vec.push_back({});
            for (int j = 1; j < n; j++) {
                vec[i - 1].push_back(arr[i][j]);
            }
        }
        // 计算生成树的个数
        sum = Determinant(vec);
        for (int k = 0; k < 30; k++) {
            memset(arr, 0, sizeof arr);
            vec.clear();
            for (int j = 1, u, v; j <= m; j++) {
                u = e[j].u;
                v = e[j].v;
                if (e[j].w & (1ll << k)) {
                    arr[u][u]++, arr[v][v]++;
                    arr[u][v]--, arr[v][u]--;
                }
            }
            for (int i = 1; i < n; i++) {
                vec.push_back({});
                for (int j = 1; j < n; j++) {
                    vec[i - 1].push_back(arr[i][j]);
                }
            }
            ll ans = Determinant(vec);
            if (!ans) continue;
            res = Add(res, Mul(1ll << k, ans));
        }
        res = Mul(res, qpow(sum, mod - 2));
        cout << res << endl;
    }
    return 0;
}

Kirakira

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值