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;
}