碎碎念
昨晚,老师在群里说了今年北京高考数学压轴题是一道OI原题后,
本蒟蒻瞬间目瞪口呆神情呆滞,只能说我老师太犇了,
一眼看穿了压轴题的真面目,让我不禁360度无死角转体膜拜。
但老码农坑人,因为这是一道紫题!!!
看题解后,记紫题祭(^▽^)
这道题至少两三年前就有了,所以码龄较长的童鞋们可能正巧刷到过,
尤其是高三的神犇们(好歹是个紫题,我这种蒟蒻一般是看都不看的),
所以一道基本没有改动
(就是原题面加强版,而解题思路却是按加强版求会好构造一些)的高考压轴题
被这些神犇们做到了那不就高兴坏了。
三年OI不是空,毕竟高考还有用!
已知
. 证明:存在
和
, 使得
给你两个可重集
,
的元素个数都为
,它们中每个元素的大小
。
请你分别找出
的子集,使得它们中的元素之和相等。
数据范围:
。
其差别就是,高考让证明求子段,原题让求子集,其实做完原题,证明自然就有了,因为正解其实是求子段。
题目原文请移步下面的链接
OI
、codeforces
、前缀和
省选/NOI-
long long
,中间提交的时候有TLE,气的老码农想踹我两脚!#include <bits/stdc++.h>
using namespace std;
struct edge {
bool b;
int l, r;
};
void out (int l1, int r1, int l2, int r2) {
cout << r1 - l1 + 1 << endl;
for (int i = l1; i <= r1; ++i) {
cout << i << " ";
}
cout << endl;
cout << r2 - l2 + 1 << endl;
for (int i = l2; i <= r2; ++i) {
cout << i << " ";
}
}
void solve(vector<long long> a, vector<long long> b, int n, bool k) {
vector<edge> ans(n);
int l = 0, r = 0;
for (; l <= n && r <= n; ++l) {
while (a[l] > b[r]) {
++r;
}
if (!ans[b[r] - a[l]].b) {
ans[b[r] - a[l]].l = l;
ans[b[r] - a[l]].r = r;
ans[b[r] - a[l]].b = true;
} else {
if (k) {
out(ans[b[r] - a[l]].l + 1, l, ans[b[r] - a[l]].r + 1, r);
} else {
out(ans[b[r] - a[l]].r + 1, r, ans[b[r] - a[l]].l + 1, l);
}
break;
}
}
}
void best_coder() {
int n;
cin >> n;
vector<long long> a(n + 1);
vector<long long> b(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
a[i] += a[i -1];
}
for (int i = 1; i <= n; ++i) {
cin >> b[i];
b[i] += b[i - 1];
}
if (a[n] < b[n]) {
solve(a, b, n, true);
} else {
solve(b, a, n, false);
}
}
void happy_coder() {
}
int main() {
// 提升cin、cout效率
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// 小码匠
best_coder();
// 最优解
// happy_coder();
// 返回
return 0;
}
END