传送门

A - Maximize The Beautiful Value

tags: 贪心、前缀和、推公式

分析

题目说明了是不降的序列,所以低于答案的贡献必定是越大的数字在后面越好,我们可以考虑如果枚举数字,让他们都往前移动位,取最大的值。

本题难点在于如何移动进行计算,如果暴力计算的话复杂度为。我们设原答案为,选择的是第个数字,观察数列变化,返现对于答案的贡献是不变的,的结果每一项都加上了。所以可以维护前缀和,取得这一部分的区间和。

  • 时间复杂度

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int const maxn = 1e5 + 10;
ll a[maxn];
int n, k;
ll pre[maxn];

int main(void) {
    FAST_IO;

    int t;
    cin >> t;
    while (t--) {
        cin >> n >> k;
        ll first = 0;
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            pre[i] = pre[i - 1] + a[i];
            first += a[i] * i;
        }
        for (int i = k + 1; i <= n; i++) {
            int x = i;
            int l = i - k;
            int r = i - 1;
            ll p = first - i * a[i] + a[i] * l;
            p += pre[r] - pre[l - 1];
            ans = max(p, ans);
        }
        cout << ans << endl;        
    }

    return 0;
}

B- 身体训练

tags: 数学

分析

因为概率相等,所以直接从第个开始枚举,计算总和。然后

时间复杂度

AC 代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int const maxn = 1e5 + 10;

int main(void) {
    FAST_IO;

    int n;
    double v, u;
    cin >> n >> v >> u;
    vector<double> c(n), d(n);
    for (auto &x : c) cin >> x;
    for (auto &x : d) cin >> x;
    double ans = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            ans += n * u / (c[i] - j * d[i] - v);
        }
    }
    cout <<fixed << setprecision(3) << ans / (n * 1.0) << endl;
    return 0;
}

C - Borrow Classroom

tags:图论、LCA

分析

对于何老师拦截的方案,可以简化为两种:

  • 何老师在节点1出等待
  • 何老师中途和同学相遇

那么设的最短距离为, 的距离为

  • ,因小Q还未到达节点1,所以老师必定可以在A点等待
  • ,老师没有小Q走的快,必定拦截
    • 如果,那么C和A分别属于节点的两个子树,不定不会相遇,无法拦截
    • 如果,因为,所以从必定会在LCA处相遇

本题需要快速查询,所有最短距离可以通过LCA进行。
复杂度

PS:本题T组输入有坑,wa了10次,从,最后发现数组没有清空,真的坑QWQ。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int const maxn = 1e5 + 10;
int vis[maxn];

struct node {
    int v, next;
}e[maxn << 1];
int head[maxn];

int fa[maxn][25];
int dep[maxn], cnt;
int n;

void add(int u, int v) {
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}
void init() {
    memset(head, -1, sizeof(head));
    memset(vis, 0, sizeof(vis));
    memset(dep, 0, sizeof(dep));
    memset(fa, 0, sizeof(fa));
    cnt = 0;
}

void dfs(int u, int v) {
    if (vis[u]) return;
    vis[u] = 1;
    fa[u][0] = v;
    for (int i = head[u]; ~i; i = e[i].next) {
        int x = e[i].v;
        if (v == x) continue;
        dep[x] = dep[u] + 1;
        dfs(x, u);
    }
}

void doubly() {
    dfs(1, 1);
    for (int j = 1; j <= 20; j++) {
        for (int i = 1; i <= n; i++) {
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
        }
    }
}

int lca(int u, int v) {
    if (dep[u] > dep[v]) {
        swap(u, v);
    }
    for (int i = 20; i >= 0; i--) {
        if ((dep[v] - (1 << i)) >= dep[u]) {
            v = fa[v][i];
        }
    }
    if (u == v) return u;
    for (int i = 20; i >= 0; i--) {
        if (fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[v][0];
}
int main(void) {
    FAST_IO;

    int t;
    cin >> t;
    while (t--) {
        init();
        int q;
        cin >> n >> q;
        for (int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            add(u, v);
            add(v, u);
        }
        doubly();
        while (q--) {
            int a, b, c;
            cin >> a >> b >> c;
            // cout << x << endl;
            int disq = abs(dep[b] - dep[1]) + 2 * abs(dep[lca(b, c)] - dep[c]);
            int dish = abs(dep[a] - dep[1]);
            int x = lca(c, a);
            if (dish > disq || (dish == disq && x == 1)) {
                cout << "NO" << endl;
            } else {
                cout << "YES" << endl;
            }
        }
    }

    return 0;
}

D - 景区路线规划

推迟是概率DP,等待明天大佬题解,先留个坑。。

E - 幸运数字Ⅱ

tags: 打表,二分查找

分析

对于满足条件的数字,可以由 获得。需要求,可以通过二分找next[i]的边界范围。再通过尺取的方式取个数。

参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int const maxn = 1e5 + 10;

vector<ll> v = {4, 7};

void bfs() {
    queue<ll> q;
    q.emplace(4);
    q.emplace(7);
    while (!q.empty()) {
        if (v.back() >= 1000000000) return;
        auto x = q.front();
        q.pop();
        q.emplace(x * 10 + 4);
        q.emplace(x * 10 + 7);
        v.emplace_back(x * 10 + 4);
        v.emplace_back(x * 10 + 7);
    }
}

int main() {
    FAST_IO;
    bfs();
    ll l, r;
    cin >> l >> r;
    ll ans = 0;
    int pos1 = lower_bound(v.begin(), v.end(), l) - v.begin();
    int pos2 = lower_bound(v.begin(), v.end(), r) - v.begin();
    if (pos1 == pos2) {
        cout << (r - l + 1) * v[pos1] << endl;
    } else {
        for (int i = pos1; i <= pos2; i++) {
            if (v[i] >= l) {
                while (l != r && l <= v[i]) {
                    ans += v[i];
                    l++;
                } 
                if (l == r) {
                    ans += v[i];
                    break;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}