2024夏令营提高1模考0718模拟赛(提高1)补题报告

2024夏令营提高1模考0718模拟赛(提高1)补题报告

\[0718模拟赛(提高1) \ \ 补题报告 \\ 2024年7月18日 \\ by \ \ \ 唐一潇 \]

一、做题情况

  • 第一题比赛 \(100 / 100\) ,赛后通过
  • 第二题比赛 \(0 / 100\) ,赛后通过
  • 第三题比赛 \(0 / 100\) ,赛后通过
  • 第四题比赛 \(0/ 100\) ,赛后通过
  • 比赛得分 \(100 / 400\) ,赛后补题 \(400\) / \(400\)

二、比赛概况

T1AC用二分,太简单了。

T2本来想骗分输出-1但是这好像构造了每一组数据都有合法解。

T3太难了,虽然知道是KMP,但是不知道怎么做。

T4链式没分,正解是线段树,暴力RE了。

三、题解报告

T1:旅行

题面:

时间限制: 1000ms

空间限制: 524288kB

题目描述

鱼大大计划环华夏自驾游游玩一圈,在他的计划中,这次旅行将在m天内完成,预计游玩n个城市,每个城市游玩x天,然后赶路开车以均速去到下一个城市,现鱼大大从海洋城市出发,按游玩顺序先后给出每个城市和上一个城市之间的距离(km),问鱼大大每天至少赶路多少距离(km)才能在m天内游玩所有城市?

输入格式

第一行两个数字n,m;分别表示要游玩的城市数量和游玩天数
接下来n行,每行两个整数ai​,x,ai​表示第i个城市和第i−1个城市之间的距离(km);x表示在第i个城市游玩的时间(天);i=1时为第一个游玩城市与鱼大大的出发地海洋城市的距离
注: 每天赶路的距离为整数

输出格式

一个整数表示鱼大大每天赶路的最少距离。如果无法再预计时间完成输出-1.

样例

Input 1

3 21
225 1
675 1
450 1

Output 1

75

样例解释

鱼大大从海洋城市出发,要在21天游玩完毕这3个城市。需每天最少赶路75km。
从海洋城市到第一城225km,需要赶路3天,游玩1天;
从第一城到第二城675km,需要赶路9天,游玩1天;
从第二城到第三城450km,需要赶路6天,游玩1天;
共21天。
若赶路距离再少,则无法在21天内完成。

数据范围

\(1≤n≤10^5\)
\(1≤a_i​,m≤10^{15}\)

做法:

  1. 理解问题:鱼大大需要在 \(m\) 天内游玩 \(n\) 个城市,每个城市游玩x天,并且需要在城市之间赶路。我们需要计算每天至少需要赶路多少距离。

  2. 计算总游玩天数:总游玩天数为\(∑^n_{i=1}​x_{i}\)​。

  3. 计算总赶路天数:总赶路天数为\(m-∑^n_{i=1}​x_{i}\)​。

  4. 计算总距离:总距离为\(∑_{i=1}^na_i\)​。

  5. 计算每天至少赶路的距离:如果总赶路天数大于0,则每天至少赶路的距离为\(\frac{​∑_{i=1}^n​{a_i}}{m−∑_{i=1}^n​x_i}\)​​。如果总赶路天数小于或等于0,则无法在预定时间内完成所有城市游玩,输出-1

  6. 考虑整数要求:每天赶路的距离必须是整数,因此我们需要向上取整

附:AC代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int INF = 2e15, N = 1e5 + 5;
int a[n], n, m, l, r = INF;
bool check(int x) {
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans += ceil(a[i] * 1.0 / x);
    }
    return ans <= m;
}
signed main() {
    ios::sync_with_stdio(false);
    scanf("%lld%lld", &n, &m);
    for (int i = 1, x; i <= n; i++) {
        scanf("%lld%lld", &a[i], &x);
        m -= x;
    }
    while (l < r) {
        int mid = l + r >> 1;
        if (check(mid)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    printf("%lld", l == INF ? -1 : l);
    return 0;
}

T2: WTP的大洗牌

题面:

时间限制: 10000ms

空间限制: 1048756kB

题目描述

image.png

输入格式

image.png

输出格式

image.png

样例

Input 1

3
1 1 1
1 2 3

Output 1

10 0

数据范围

做法:

由于前 \(10\%\)\(n=1\)

\[a^2+b^2=x^2+y^2 \]

直接输出 \(a,b\) 即可

由于另外 \(20\%\)\(n=2\)

\[\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (a_1^2+b_1^2)(a_2^2+b_2^2)\\ =a_1^2\times a_2^2 +a_1^2\times b_2^2 + b_1^2\times a_2^2 + b_1^2\times b_2^2\\ =(a_1b_1)^2+(a_2b_1)^2+(a_1b_2)^2+(a_2b_2)^2\\ =(a_1b_1)^2+2a_1a_2b_1b_2+(a_2b_1)^2+(a_1b_2)^2-2a_1a_2b_1b_2+(a_2b_2)^2\\ =(a_1b_1+a_2b_2)^2+(a_2b_1-a_1b_2)^2 \]

直接可以得出答案

附:AC代码

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
int n, a[500009], b[500009], m = 1, x = 0, y = 0;
signed main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    x = a[1], y = b[1];
    for (int i = 2, t1, t2; i <= n; i++) {
        t1 = x, t2 = y;
        x = t1 * a[i] + t2 * b[i];
        y = t1 * b[i] - t2 * a[i];
    }
    cout << x << ' ' << y;
}

T3:第一题

题面:

样例

Input 1

abyzuv
1

Output 1

0
17292
2265252
5092492668516
667116539575596
5552418600567558216

Input 2

ctagqkeu
2

Output 2

4894148
1324957402927832
7501175624655915608
7097807190249508344

做法:

考虑KMP

唯一需要注意的是这个就是强制在线(就是一个不能错)。

附:AC代码

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int inf = 1e17;
const double eps = 1e-6;
const int B = 131;
char s[5000005];
int k, kmp[5000005], hash1[5000005], hash2[5000005], ans[5000005], pw[5000005];
signed main() {
    freopen("easy.in", "r", stdin);
    freopen("easy.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
    cin >> s + 1 >> k;
    int n = strlen(s + 1);
    pw[1] = B * B, pw[0] = 1;
    for (int i = 2; i <= n; i++)
        pw[i] = B * B * pw[i - 1];
    int j = 0;
    for (int i = 1; i <= n; i++) {
        s[i] = (ans[i - 1] + s[i] - 'a') % 26 + 'a';
        if (i != 1) {
            while (j && s[j + 1] != s[i])
                j = kmp[j];
            if (s[i] == s[j + 1])
                j++;
            kmp[i] = j;
        }
        hash1[i] = hash1[i - 1] * B * B + (s[i] - 'a') * B;
        hash2[i] = hash2[i - 1] + (s[i] - 'a') * pw[i - 1];
        ans[i] = hash1[i] + hash2[i] + ans[j];
    }
    int num = 0;
    for (int i = 1; i <= n; i++) {
        num ^= ans[i];
        if (!(i % k)) {
            cout << num << '\n';
            num = 0;
        }
    }
    return 0;
}

T4:WTP的通缉

题面:

样例

Input 1

5 6
4 2 4
2 1 3
4 3 6
2 5 1
1 2 3 4
1 1 2 3
1 1 2 5
2 3 4 5
4 4 5 5
1 2 4 5

Output 1

13
13
13
11
5
7

做法:

![(ef0bb2c7b2f8dd7a3dd2547ca84d1fb6cc3907ec.png (600×220) (xinyoudui.com)

f4bfa4006610aa0fb5230b76e142987cfdadd9fa.png (616×528) (xinyoudui.com)

附:AC代码

#include <bits/stdc++.h>
#define ll long long
#define ls(p) p << 1
#define rs(p) p << 1 | 1
template <typename T>
void read(T& x) {
    x = 0;
    int flag = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            flag = -1;
    for (; isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    x *= flag;
}
using namespace std;
const int maxn = 100010;
int n, q, head[maxn], tot, pa[maxn][20], dep[maxn], lg[maxn];
ll dis[maxn];
struct Edge {
    int to, nxt, w;
} edge[maxn << 1];
struct Node {
    int l, r;
    ll sum;
} t[maxn << 2], res1, res2;
void add(int u, int v, int w) {
    edge[++tot].to = v, edge[tot].w = w, edge[tot].nxt = head[u], head[u] = tot;
}
void dfs(int u, int fa) {
    for (int i = head[u]; i; i = edge[i].nxt)
        if (edge[i].to != fa) {
            int v = edge[i].to, w = edge[i].w;
            pa[v][0] = u, dep[v] = dep[u] + 1, dis[v] = dis[u] + w;
            dfs(v, u);
        }
}
int lca(int u, int v) {
    if (dep[u] < dep[v])
        swap(u, v);
    int x = dep[u] - dep[v];
    while (x)
        u = pa[u][lg[x & -x]], x -= x & -x;
    if (u == v)
        return u;
    for (int k = min(lg[dep[u]], lg[dep[v]]); k >= 0; k--)
        if (pa[u][k] != pa[v][k])
            u = pa[u][k], v = pa[v][k];
    return pa[u][0];
}
ll query(int x, int y) {
    return dis[x] + dis[y] - 2ll * dis[lca(x, y)];
}
void push_up(int p) {
    int a = t[ls(p)].l, b = t[ls(p)].r, c = t[rs(p)].l, d = t[rs(p)].r;
    t[p] = t[ls(p)].sum > t[rs(p)].sum ? t[ls(p)] : t[rs(p)];
    ll w1 = query(a, c), w2 = query(a, d), w3 = query(b, c), w4 = query(b, d);
    if (w1 > t[p].sum)
        t[p].sum = w1, t[p].l = a, t[p].r = c;
    if (w2 > t[p].sum)
        t[p].sum = w2, t[p].l = a, t[p].r = d;
    if (w3 > t[p].sum)
        t[p].sum = w3, t[p].l = b, t[p].r = c;
    if (w4 > t[p].sum)
        t[p].sum = w4, t[p].l = b, t[p].r = d;
}
void build(int p, int l, int r) {
    if (l == r) {
        t[p].l = t[p].r = l, t[p].sum = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(ls(p), l, mid), build(rs(p), mid + 1, r);
    push_up(p);
}
void query(int p, int l, int r, int ql, int qr, Node& res) {
    if (ql <= l && r <= qr) {
        if (!res.l)
            res = t[p];
        else {
            int a = res.l, b = res.r, c = t[p].l, d = t[p].r;
            if (t[p].sum > res.sum)
                res = t[p];
            ll w1 = query(a, c), w2 = query(a, d), w3 = query(b, c), w4 = query(b, d);
            if (w1 > res.sum)
                res.sum = w1, res.l = a, res.r = c;
            if (w2 > res.sum)
                res.sum = w2, res.l = a, res.r = d;
            if (w3 > res.sum)
                res.sum = w3, res.l = b, res.r = c;
            if (w4 > res.sum)
                res.sum = w4, res.l = b, res.r = d;
        }
        return;
    }
    int mid = (l + r) >> 1;
    if (ql <= mid)
        query(ls(p), l, mid, ql, qr, res);
    if (qr > mid)
        query(rs(p), mid + 1, r, ql, qr, res);
}
int main() {
    read(n), read(q);
    lg[1] = 0;
    for (int i = 2; i <= n; i++)
        lg[i] = lg[i >> 1] + 1;
    for (int i = 1; i < n; i++) {
        int u, v, w;
        read(u), read(v), read(w);
        add(u, v, w), add(v, u, w);
    }
    dfs(1, 0);
    for (int j = 1; j <= 16; j++)
        for (int i = 1; i <= n; i++)
            pa[i][j] = pa[pa[i][j - 1]][j - 1];
    build(1, 1, n);
    while (q--) {
        int l1, r1, l2, r2;
        read(l1), read(r1), read(l2), read(r2);
        res1.l = res1.r = res2.l = res2.r = 0, res1.sum = res2.sum = 0;
        query(1, 1, n, l1, r1, res1), query(1, 1, n, l2, r2, res2);
        printf("%lld\n", max(max(query(res1.l, res2.l), query(res1.l, res2.r)), max(query(res1.r, res2.l), query(res1.r, res2.r))));
    }
    return 0;
}, lca(a1, b2)), max(lca(b1, a2), lca(b1, b2))));
    }
    return 0;
}

四、赛后总结

说句闲话,研究OI的最好方法是:

  1. 成功经验:在第一题中取得满分,显示了我们在某些领域的扎实基础和快速反应能力。这种成功经验值得我们总结和复制。

  2. 不足之处:在第二、第三和第四题中,我们未能在比赛中得分,这暴露了我们在某些知识点上的薄弱环节。我们需要在未来加强对这些领域的学习和训练。

  3. 改进措施:为了在未来的比赛中取得更好的成绩,我们需要:

    • 加强基础知识的学习,特别是那些在比赛中表现不佳的领域。
    • 提高团队的协作能力,确保每个成员都能在团队中发挥最大的作用。
    • 增加实战演练,通过模拟比赛来提高我们的应变能力和解题速度。

通过这次比赛,我们不仅看到了自己的不足,也发现了潜力。我们相信,通过不断的努力和学习,我们能够在未来的挑战中取得更好的成绩。让我们以这次比赛为契机,继续前进,不断超越自我。

附:随笔

OI之路:勇往直前

一、自我反思与成长

在这次比赛中,我深刻地认识到了自己的不足,并明确了未来的训练目标。这不仅是一次自我检验的机会,更是一次自我提升的契机。正如李白所言:“乘风破浪会有时,直挂云帆济沧海”,在茫茫人海中,我们虽然弱小,但也要勇敢地面对挑战,展现出“苔花如米小,也学牡丹开”的精神。

二、努力的价值与意义

通过这次比赛,我也看到了自己努力的成果。这不仅给予了我继续在OI之路上披荆斩棘的勇气与动力,更让我明白,每一次的努力都是向成功更进一步。正如“轻肌弱骨散幽葩,更将金蕊泛流霞”,即使我们的力量微小,也要有不断向上的决心和勇气。

三、高处的风景与挑战

“仁者见仁,智者见智”,成为优秀的人,看到的世界是不一样的。每当你登上一座新的山峰,都会享受那里细腻清风的洗涤,与明媚阳光的沐浴。与其在山脚说山顶是令人心驰神往的,不如立刻付诸行动。高处的风景虽然美丽,但也需要我们不断地努力和攀登。

四、保持谦逊与虚心

余秋雨在《文化苦旅》中说道,“繁华转眼凋零,喧嚣是短命的别名”。我们不能在拥有一点知识后就自我满意,“水满则溢,月满则亏,自满则败,自矜则愚”。我们要保持虚心的心态与视角,不耻下问,同时,向高处攀登。

五、持续的努力与奔跑

一个跑者,在一场马拉松中,是不会停下的,因为一旦停下,就很难再重新跑起来。在一眼望不到边的OI赛道上,我们或快,或慢,或前,或后,但这些都不重要。从现在起,不要停下,一直跑下去吧。

六、结语

综上所述,努力吧,OIer!“可不要辜负自己的努力啊,2024还有机会在等着我呢!”让我们以这次比赛为契机,继续前进,不断超越自我。

“可不要辜负自己的努力啊,2024还有机会在等着我呢!” ——Syx

posted @ 2024-07-18 19:48  TangyixiaoQAQ  阅读(133)  评论(0)    收藏  举报