[USACO23FEB] Equal Sum Subarrays G
我来教大家如何打暴力。
首先,根据题面,假设我们当前要修改第 个数。如果两个区间都包含 ,此时无论做何修改差都不变,都不包含同理。因此,我们找的两个区间应为:其中一个包含第 项,而另一个不含。
由于 非常小,我想到将所有符合条件的区间和都存下来,这个过程预处理出来或者套个前缀和都可以。之后,就是在两个数组中找绝对值差最小。排个序然后双指针搞一下就可以。
使用 std::sort
的时间复杂度为 ,还是很难通过。我经过简单的卡常拿到了 3.07s 的好成绩。于是我一怒之下换成基数排序就过了。
#include <bits/extc++.h>
using namespace std;
namespace pbds = __gnu_pbds;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
template <typename T> class PrefixSum {
vector<T> sum;
public:
template <typename InputIterator, typename = _RequireInputIter<InputIterator>>
PrefixSum(InputIterator begin, size_t n): sum(n + 1) {
typename vector<T>::iterator it = next(sum.begin());
*(it++) = *begin;
for (size_t i = 1; i < n; ++i, ++it) *it = *prev(it) + *++begin;
}
T get_sum(size_t m, size_t n) { return sum[n] - sum[m]; }
T get_val(size_t m) { return get_sum(m, m + 1); }
T operator[](size_t m) { return get_val(m); }
size_t size(void) { return sum.size(); }
};
// 我的基数排序模板仅支持无符号整数,因此有全部加一个偏移量到正数
template <typename ForwardIterator,
typename = is_unsigned<typename ForwardIterator::value_type>>
void radixSort(ForwardIterator first, ForwardIterator last) {
constexpr ui P = 8;
constexpr size_t T =
numeric_limits<typename ForwardIterator::value_type>::digits / P;
size_t n = distance(first, last);
ui W = 0;
auto* dat = new typename ForwardIterator::value_type[n];
for (size_t i = 0; i < T; ++i, W += P) {
array<size_t, 1u << P> cnt{};
for_each(first, last, [&](typename ForwardIterator::reference const x) {
++cnt[(x >> W) & ((1u << P) - 1)];
});
partial_sum(cnt.begin(), cnt.end(), cnt.begin());
rotate(cnt.begin(), prev(cnt.end()), cnt.end()), cnt[0] = 0;
for_each(first, last, [&](typename ForwardIterator::reference const x) {
dat[cnt[(x >> W) & ((1u << P) - 1)]++] = x;
});
copy(dat, dat + n, first);
}
delete[] dat;
}
int main(void) {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
size_t n;
fin >> n;
vector<li> a(n);
for (li& i : a) fin >> i;
PrefixSum<li> p(a.begin(), n);
for (size_t i = 0; i < n; ++i) {
vector<uli> s, t;
for (size_t j = 0; j < i; ++j)
for (size_t k = j; k < i; ++k)
s.emplace_back((uli)p.get_sum(j, k + 1) - numeric_limits<li>::min());
for (size_t j = i + 1; j < n; ++j)
for (size_t k = j; k < n; ++k)
s.emplace_back((uli)p.get_sum(j, k + 1) - numeric_limits<li>::min());
uli ans = numeric_limits<uli>::max();
for (size_t j = 0; j <= i; ++j)
for (size_t k = i; k < n; ++k)
t.emplace_back((uli)p.get_sum(j, k + 1) - numeric_limits<li>::min());
radixSort(s.begin(), s.end()), radixSort(t.begin(), t.end());
vector<uli>::iterator it = s.begin();
for (uli i : t) {
while (it != s.end() && *it < i) ++it;
if (it != s.end()) ans = min(ans, *it - i);
if (it != s.begin()) ans = min(ans, i - *prev(it));
}
fout << ans << '\n';
}
return 0;
}