题意:给你两个长度为n的序列,在两个序列中分别找出一个子集,使这两个子集的总和相等。输出方案。
思路:大概,这个题很多条件都是用来搞事的。比如,输出-1就很有迷惑性,事实上这题并不可能无解。而且,如果子序列改为子段的话,会更好想一些。
总之,这道题的思维性很强。我们可以维护两个前缀和数组
s
a
[
n
]
,
s
b
[
n
]
sa[n],sb[n]
sa[n],sb[n],分别代表两个序列的前缀和。
序列a中子段的和可以表示为
s
a
[
i
]
−
s
a
[
j
]
(
n
≥
i
≥
j
≥
0
)
sa[i]-sa[j](n\geq i\geq j\geq 0)
sa[i]−sa[j](n≥i≥j≥0)
判断是否存在两个子段,保证
s
a
[
i
]
−
s
a
[
j
]
=
s
b
[
i
′
]
−
s
b
[
j
′
]
(
n
≥
i
≥
j
≥
0
,
n
≥
i
′
≥
j
′
≥
0
)
sa[i]-sa[j]=sb[i']-sb[j'](n\geq i\geq j\geq 0,n\geq i'\geq j'\geq 0)
sa[i]−sa[j]=sb[i′]−sb[j′](n≥i≥j≥0,n≥i′≥j′≥0)
移项后可以得到
s
a
[
i
]
−
s
b
[
i
′
]
=
s
a
[
j
]
−
s
b
[
j
′
]
sa[i]-sb[i']=sa[j]-sb[j']
sa[i]−sb[i′]=sa[j]−sb[j′]
而对于每一个
s
a
[
i
]
sa[i]
sa[i],总能找到一个
s
b
[
i
′
]
sb[i']
sb[i′],使得
s
a
[
i
]
−
s
b
[
j
′
]
sa[i]-sb[j']
sa[i]−sb[j′]的值在区间
[
0
,
n
−
1
]
[0,n-1]
[0,n−1]范围内。
由鸽巢原理可以得到,对于
[
0
,
n
]
[0,n]
[0,n]范围内的所有
i
i
i,必然存在两个
s
a
[
i
]
−
s
b
[
i
′
]
sa[i]-sb[i']
sa[i]−sb[i′]的值相同。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
const int maxn = 1e6 + 10;
const ll mod = 998244353;
const ld PI = acos(-1.0);
int n, p[maxn];
ll s1[maxn], s2[maxn], a[maxn], b[maxn];
set<ll> s;
int main() {
__;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
s1[i] = s1[i - 1] + a[i];
}
for (int i = 1; i <= n; ++i) {
cin >> b[i];
s2[i] = s2[i - 1] + b[i];
}
if (s1[n] < s2[n]) {
int pos = 0;
for (int i = 0; i <= n; ++i) {
while (s2[pos] < s1[i])++pos;
p[i] = pos;
if (s.count(s1[i] - s2[p[i]]) == 0)
s.insert(s1[i] - s2[p[i]]);
else {
for (int j = i - 1; j >= 0; --j) {
if (s1[i] - s2[p[i]] == s1[j] - s2[p[j]]) {
cout << i - j << endl;
for (int k = j + 1; k <= i; ++k)cout << k << ' ';
cout << endl;
cout << p[i] - p[j] << endl;
for (int k = p[j] + 1; k <= p[i]; ++k)cout << k << ' ';
cout << endl;
return 0;
}
}
}
}
} else {
int pos = 0;
for (int i = 0; i <= n; ++i) {
while (s1[pos] < s2[i])++pos;
p[i] = pos;
if (s.count(s2[i] - s1[p[i]]) == 0)
s.insert(s2[i] - s1[p[i]]);
else {
for (int j = i - 1; j >= 0; --j) {
if (s2[i] - s1[p[i]] == s2[j] - s1[p[j]]) {
cout << p[i] - p[j] << endl;
for (int k = p[j] + 1; k <= p[i]; ++k)cout << k << ' ';
cout << endl;
cout << i - j << endl;
for (int k = j + 1; k <= i; ++k)cout << k << ' ';
cout << endl;
return 0;
}
}
}
}
}
cout << -1 << endl;
return 0;
}