2026-08-27~29 hetao1733837 的刷题记录

2026-08-27~29 hetao1733837 的刷题记录

LGP8797 蓝桥杯 2022 国 A 三角序列

原题链接:蓝桥杯 2022 国 A 三角序列

分析

对哦,我 O ( ∑ a i ) O(\sum{a_i}) O(∑ai) 建树显然爆爆爆。期望获得多达 50 p t s 50pts 50pts。

我们需要优化一下......树套树/tuu

但是,根本开不下啊/ll

难道要离散化?

离线???!!!

我离线下来,然后,对于那些不跨过"边界"的三角形,我们直接做,反之,我们重新建树吗?耗不起......思考一下,总之感觉这个思路非常有前途。


显然很假。怎么做呢?显然要二分。

那么,我们发现,对于询问 l r,我们可以进行一些分类讨论,对于 l r 同属于同一个三角形,显然有:

cpp 复制代码
int calc(int id, int l, int r, int h){
	int vl, vr;
	if (b[id] == 0){
		vl = l;
		vr = r;
	}
	else{
		vl = a[id] - r + 1;
		vr = a[id] - l + 1;
	}
	if (h <= vl){
		return h * (vr - vl + 1);
	}
	else if (h > vr){
		return (vr - vl) * (r - l + 1);
	}
	else{
		return h * (vr - h) + (vl + h) * (h - vl + 1) / 2;
	}
}

需要注意的是,他是一个实体的阶梯,所以,等差数列管不到两个,只能管一个。

对于 l r 属于不同的三角形,这个是不好做的。但是,细想一下,我们发现,他是两边加上中间。中间是一个类似于前缀和的东西可以预处理,当然在线段树上是好做的,那么,需要考虑的就是两边,两边其实是两个梯形状物,那么,似乎也不是困难的。两边可以按照 calc 函数直接做,但是,对于中间的,我们不是很好算,那么,不妨使用 正难则反 的狭义 hxf 容斥,用整体减去不合法的,发现似乎是一些小尖尖,三角形是好做的,得到公式:

1 2 ∑ i = 1 k h i 2 − ( 2 h − 1 ) ∑ i = 1 k h i + ( h 2 − h ) × k \dfrac{1}{2}\\sum\\limits_{i=1}\^{k}{h_i\^2}-(2h-1)\\sum\\limits_{i=1}\^{k}{h_i}+(h\^2-h)\\times k 21i=1∑khi2−(2h−1)i=1∑khi+(h2−h)×k

我们拿主席树维护一下 ∑ i = 1 k h i 2 \sum\limits_{i=1}^{k}{h_i^2} i=1∑khi2、 ∑ i = 1 k h i \sum\limits_{i=1}^{k}{h_i} i=1∑khi、 k k k 即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005, V = 1000005;
int n, m, a[N], b[N];
struct node{
    int ls, rs, sum, pw, cnt;
}tr[N << 5];
int rt[N << 5], tot;
int calc(int id, int l, int r, int h){
    int vl, vr;
    if (b[id] == 0){
        vl = l;
        vr = r;
    }
    else{
        vl = a[id] - r + 1;
        vr = a[id] - l + 1;
    }
    if (h <= vl){
        return h * (vr - vl + 1);
    }
    else if (h > vr){
        return (vl + vr) * (r - l + 1) / 2;
    }
    else{
        return h * (vr - h) + (vl + h) * (h - vl + 1) / 2;
    }
}
struct president_segtree{
    void pushup(int p){
        tr[p].sum = tr[tr[p].ls].sum + tr[tr[p].rs].sum;
        tr[p].pw = tr[tr[p].ls].pw + tr[tr[p].rs].pw;
        tr[p].cnt = tr[tr[p].ls].cnt + tr[tr[p].rs].cnt;
    }
    void modify(int &p, int pre, int l, int r, int s, int val){
        p = ++tot;
        tr[p] = tr[pre];
        if (l == r){
            tr[p].sum += val;
            tr[p].pw += val * val;
            tr[p].cnt += 1;
            return ;
        } 
        int mid = (l + r) >> 1;
        if (s <= mid)
            modify(tr[p].ls, tr[pre].ls, l, mid, s, val);
        else
            modify(tr[p].rs, tr[pre].rs, mid + 1, r, s, val);
        pushup(p);
    }
    int query_sum(int p, int pre, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return tr[p].sum - tr[pre].sum;
        }
        int mid = (l + r) >> 1;
        int res = 0;
        if (s <= mid)
            res += query_sum(tr[p].ls, tr[pre].ls, l, mid, s, t);
        if (t > mid)
            res += query_sum(tr[p].rs, tr[pre].rs, mid + 1, r, s, t);
        return res;
    }
    int query_pw(int p, int pre, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return tr[p].pw - tr[pre].pw;
        }
        int mid = (l + r) >> 1;
        int res = 0;
        if (s <= mid)
            res += query_pw(tr[p].ls, tr[pre].ls, l, mid, s, t);
        if (t > mid)
            res += query_pw(tr[p].rs, tr[pre].rs, mid + 1, r, s, t);
        return res;
    }
    int query_cnt(int p, int pre, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return tr[p].cnt - tr[pre].cnt;
        }
        int mid = (l + r) >> 1;
        int res = 0;
        if (s <= mid)
            res += query_cnt(tr[p].ls, tr[pre].ls, l, mid, s, t);
        if (t > mid)
            res += query_cnt(tr[p].rs, tr[pre].rs, mid + 1, r, s, t);
        return res;
    }
}T;
int sum[N], pre[N];
int L[N], R[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++){
        cin >> a[i] >> b[i];
        T.modify(rt[i], rt[i - 1], 1, V, a[i], a[i]);
        sum[i] = sum[i - 1] + a[i];
        pre[i] = pre[i - 1] + a[i] * (1 + a[i]) / 2;
        L[i] = sum[i - 1] + 1;
        R[i] = sum[i];
    }
    for (int cs = 1, l, r, v; cs <= m; cs++){
        cin >> l >> r >> v;
        int pos1 = lower_bound(sum + 1, sum + n + 1, l) - sum;
        int pos2 = lower_bound(sum + 1, sum + n + 1, r) - sum;
        int ll = 1, rr = V;
        int ans = -1;
        while (ll <= rr){
            int mid = (ll + rr) >> 1;
            int res;
            if (pos1 == pos2){
                res = calc(pos1, l - L[pos1] + 1, r - L[pos1] + 1, mid);
            }
            else{
                int tmp1 = T.query_sum(rt[pos2 - 1], rt[pos1], 1, V, mid, V) 
                         - T.query_sum(rt[pos2 - 1], rt[pos1], 1, V, mid, mid);
                int tmp2 = T.query_pw(rt[pos2 - 1], rt[pos1], 1, V, mid, V)
                         - T.query_pw(rt[pos2 - 1], rt[pos1], 1, V, mid, mid);
                int tmp3 = T.query_cnt(rt[pos2 - 1], rt[pos1], 1, V, mid, V)
                         - T.query_cnt(rt[pos2 - 1], rt[pos1], 1, V, mid, mid);
                res = (tmp2 - 2 * tmp1 * mid + tmp3 * mid * mid + tmp1 - tmp3 * mid) / 2;
                res = pre[pos2 - 1] - pre[pos1] - res;
                res += calc(pos1, l - L[pos1] + 1, R[pos1] - L[pos1] + 1, mid);
                res += calc(pos2, 1, r - L[pos2] + 1, mid);
            }
            if (res >= v){
                ans = mid;
                rr = mid - 1;
            }
            else{
                ll = mid + 1;
            }
        } 
        cout << ans << '\n';
    }
    return 0;
}

LGP12342 蓝桥杯 2025 省 B/Python B 第二场 数列差分

原题链接:蓝桥杯 2025 省 B/Python B 第二场 数列差分

分析

最开始统计的还是本质为 A A A 的,卡了 17min ,总算是搞出来吧......其实要是场上知道自己能拿 85 p t s 85pts 85pts 甚至 60 p t s 60pts 60pts,我可能就撤离了。不过尽力拿正解吧,毕竟这是一个橙。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n;
int a[N], b[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; i++){
        cin >> b[i];
    }
    sort(b + 1, b + n + 1);
    int res = 0;
    int i = 1, j = 1; 
    while (i <= n && j <= n){
        if (a[i] > b[j]){
            i++;
            j++;
            res++;
        }
        else{
            i++;
        }
    }
    cout << n - res; //之前本质是在统计 A 
}

LGP15855 蓝桥杯第二届国际赛 汉诺塔问题

原题链接:蓝桥杯第二届国际赛 汉诺塔问题

分析

努力打暴力的孩子......

直接模拟汉诺塔可以获得 50 p t s 50pts 50pts!!!

然后我试图寻找规律,发现我们的整场中获得了多达 110 − 135 p t s 110-135pts 110−135pts,完美一等,准备撤离

剩下的,我们发现直接递归做就行了......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 105;
const int LIM = 1e18 + 500;
struct node{
    int ans[7];
}dp[N][3][3];
node pushup(node x, node y){
    node res;
    for (int i = 1; i <= 6; i++){
        res.ans[i] = x.ans[i] + y.ans[i];
    }
    return res;
}
int pw[N];
node hano(int n, int x, int y, int id, int frm, int to, int tra){
    node res = node();
    if (n == 0 || x > y) 
        return res;
    int tot = pw[n] - 1;
    int sum = pw[n - 1];
    if (x <= id + 1 && id + tot <= y)
        return dp[n][frm][to];
    if (x < id + sum)
        res = pushup(res, hano(n - 1, x, min(y, id + sum - 1), id, frm, tra, to));
    if (x <= id + sum && id + sum <= y)
        res = pushup(res, dp[1][frm][to]);
    if (y > id + sum)
        res = pushup(res, hano(n - 1, max(x, id + sum + 1), y, id + sum, tra, to, frm));
    return res;
}
int n, x, y;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> x >> y;
    pw[0] = 1;
    for (int i = 1; i <= n; i++){
        if (pw[i - 1] > LIM / 2) 
            pw[i] = LIM;
        else 
            pw[i] = pw[i - 1] * 2;
    }
    dp[1][0][1].ans[1] = 1;
    dp[1][0][2].ans[2] = 1;
    dp[1][1][0].ans[3] = 1;
    dp[1][1][2].ans[4] = 1;
    dp[1][2][0].ans[5] = 1;
    dp[1][2][1].ans[6] = 1; 
    for (int i = 2; i <= n; i++){
        dp[i][0][2] = pushup(pushup(dp[i - 1][0][1], dp[1][0][2]), dp[i - 1][1][2]);
        dp[i][0][1] = pushup(pushup(dp[i - 1][0][2], dp[1][0][1]), dp[i - 1][2][1]);
        dp[i][1][2] = pushup(pushup(dp[i - 1][1][0], dp[1][1][2]), dp[i - 1][0][2]);
        dp[i][1][0] = pushup(pushup(dp[i - 1][1][2], dp[1][1][0]), dp[i - 1][2][0]);
        dp[i][2][0] = pushup(pushup(dp[i - 1][2][1], dp[1][2][0]), dp[i - 1][1][0]);
        dp[i][2][1] = pushup(pushup(dp[i - 1][2][0], dp[1][2][1]), dp[i - 1][0][1]);
    }
    node res = hano(n, x, y, 0, 0, 2, 1);
    for (int i = 1; i <= 6; i++){
        cout << res.ans[i] << '\n';
    }
    return 0;
}

LGP3168 CQOI2015 任务查询系统

原题链接:CQOI2015 任务查询系统

分析

天啊,我有点烫了。

首先,你权值线段树就不要考虑时间维度了,你直接做权值的离散化不就行了?

然后因为你是权值,所以,你肯定需要一个个数之类的东西对吧,然后你做完了。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005; 
int m, n;
struct node{
    int s, e, p;
}inp[N];
int len, b[N];
int rt[N];
struct tree{
    int ls, rs, cnt, sum;
}tr[N * 40];
int tot = 0;
struct president_segtree{
    void modify(int &p, int pre, int l, int r, int s, int val){
        p = ++tot;
        tr[p] = tr[pre];
        tr[p].cnt += val;
        tr[p].sum += val * b[s];
        if (l == r) 
            return ;
        int mid = (l + r) >> 1;
        if (s <= mid)
            modify(tr[p].ls, tr[pre].ls, l, mid, s, val);
        else
            modify(tr[p].rs, tr[pre].rs, mid + 1, r, s, val);
    }
    int query(int p, int l, int r, int k){
        if (l == r){
            return k * b[l];
        }
        int mid = (l + r) >> 1;
        int leftCnt = tr[tr[p].ls].cnt;
        if (k <= leftCnt)
            return query(tr[p].ls, l, mid, k);
        else
            return tr[tr[p].ls].sum + query(tr[p].rs, mid + 1, r, k - leftCnt);
    }
}T; 
vector<int> st[N], ed[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> m >> n;
    for (int i = 1; i <= m; i++){
        cin >> inp[i].s >> inp[i].e >> inp[i].p;
        b[i] = inp[i].p;
        st[inp[i].s].push_back(i);
        ed[inp[i].e + 1].push_back(i);
    }
    sort(b + 1, b + m + 1);
    len = unique(b + 1, b + m + 1) - b - 1;
    rt[0] = 0;
    for (int i = 1; i <= n; i++){
        int tmp = rt[i - 1];
        for (auto v : st[i]){
            int pos = lower_bound(b + 1, b + len + 1, inp[v].p) - b;
            T.modify(tmp, tmp, 1, len, pos, 1);
        }
        for (auto v : ed[i]){
            int pos = lower_bound(b + 1, b + len + 1, inp[v].p) - b;
            T.modify(tmp, tmp, 1, len, pos, -1);
        }
        rt[i] = tmp;
    }
    int ans = 1;
    for (int i = 1, x, A, B, C; i <= n; i++){
        cin >> x >> A >> B >> C;
        int k = 1 + (A * ans + B) % C;
        int total = tr[rt[x]].cnt;
        if (k > total)
            ans = tr[rt[x]].sum;
        else
            ans = T.query(rt[x], 1, len, k);
        cout << ans << '\n';
    }
    return 0;
}
相关推荐
chen<>24 分钟前
C++ 六种 memory_order:从原子性到线程间可见性.md
java·linux·开发语言·c++
云淡风轻~窗明几净28 分钟前
宇宙管理学猜想
算法·图论
会周易的程序员34 分钟前
企业私有 AI 算力服务器架构设计:异构四节点 + QUIC 微服务
运维·服务器·c++·人工智能·微服务·架构
春风解人意35 分钟前
从零开始学习嵌入式P28----线程
c语言·学习·算法
m0_7345717637 分钟前
深入理解C++ 类型转换<三>const_cast
开发语言·c++
luj_176838 分钟前
合法避税与投资评估实战指南
c语言·开发语言·网络·经验分享·算法
库玛西44 分钟前
Linux网络编程:HTTP/HTTPS协议核心技术全解析
linux·运维·服务器·网络·c++·http·https
Bruce_Liuxiaowei1 小时前
驴滑块拼图游戏:从19世纪的纸片谜题到数学博弈论
人工智能·算法
一直C1 小时前
Linux系统编程|信号进阶 + SystemV IPC(消息队列、共享内存)
linux·c语言·开发语言·算法·青少年编程·vim