本文涉及的基础知识点
排序
[USACO23FEB] Equal Sum Subarrays G
题面翻译
题目描述
注意:本题的时间限制为 3 秒,为默认时间的 1.5 倍。
FJ 给了 Bessie 一个长度为 N N N 的数组 a a a( 2 ≤ N ≤ 500 , − 1 0 15 ≤ a i ≤ 1 0 15 2 \leq N \leq 500, -10^{15} \leq a_i \leq 10^{15} 2≤N≤500,−1015≤ai≤1015),其中所有 N ( N + 1 ) 2 \dfrac{N(N+1)}{2} 2N(N+1) 个连续子数组的和都是不同的。对于每个下标 i ∈ [ 1 , N ] i \in [1,N] i∈[1,N],帮助 Bessie 计算最小的改变量,使得数组中存在两个不同的连续子数组的和相等。
输入格式
第一行包含一个整数 N N N,表示数组的长度。
第二行包含 a 1 , ⋯ , a N a_1,\cdots,a_N a1,⋯,aN,即数组 a a a 的元素,按顺序给出。
输出格式
对于每个下标 i ∈ [ 1 , N ] i \in [1,N] i∈[1,N],输出一行一个整数,表示改变 a i a_i ai 的最小改变量。
样例 1 的解释
将 a 1 a_1 a1 减少 2 2 2,可以使得 a 1 + a 2 = a 2 a_1+a_2=a_2 a1+a2=a2。类似地,将 a 2 a_2 a2 增加 3 3 3,可以使得 a 1 + a 2 = a 1 a_1+a_2=a_1 a1+a2=a1。
样例 2 的解释
将 a 1 a_1 a1 增加 1 1 1 或将 a 3 a_3 a3 减少 1 1 1,可以使得 a 1 = a 3 a_1=a_3 a1=a3。将 a 2 a_2 a2 增加 6 6 6,可以使得 a 1 = a 1 + a 2 + a 3 a_1=a_1+a_2+a_3 a1=a1+a2+a3。
评分标准
- 测试点 3 3 3: N ≤ 40 N \leq 40 N≤40
- 测试点 4 4 4: N ≤ 80 N \leq 80 N≤80
- 测试点 5 − 7 5-7 5−7: N ≤ 200 N \leq 200 N≤200
- 测试点 8 − 16 8-16 8−16:无额外限制。
题目描述
Note: The time limit for this problem is 3s, 1.5x the default.
FJ gave Bessie an array a a a of length N ( 2 ≤ N ≤ 500 , − 1 0 15 ≤ a i ≤ 1 0 15 ) N(2 \le N \le 500,−10^{15} \le a_i \le 10^{15}) N(2≤N≤500,−1015≤ai≤1015) with all N ( N + 1 ) 2 \dfrac{N(N+1)}{2} 2N(N+1) contiguous subarray sums distinct. For each index i ∈ [ 1 , N ] i \in [1,N] i∈[1,N], help Bessie compute the minimum amount it suffices to change ai by so that there are two different contiguous subarrays of a with equal sum.
输入格式
The first line contains N N N.
The next line contains a 1 , ⋯ , a N a_1, \cdots ,a_N a1,⋯,aN
(the elements of a a a, in order).
输出格式
One line for each index i ∈ [ 1 , N ] i \in [1,N] i∈[1,N].
样例 #1
样例输入 #1
2
2 -3
样例输出 #1
2
3
样例 #2
样例输入 #2
3
3 -10 4
样例输出 #2
1
6
1
提示
Explanation for Sample 1
Decreasing a 1 a_1 a1 by 2 2 2 would result in a 1 + a 2 = a 2 a_1+a_2=a_2 a1+a2=a2. Similarly, increasing a 2 a_2 a2 by 3 3 3 would result in a 1 + a 2 = a 1 a_1+a_2=a_1 a1+a2=a1.
Explanation for Sample 2
Increasing a1 or decreasing a 3 a_3 a3 by 1 1 1 would result in a 1 = a 3 a_1=a_3 a1=a3. Increasing a 2 a_2 a2 by 6 6 6 would result in a 1 = a 1 + a 2 + a 3 a_1=a_1+a_2+a_3 a1=a1+a2+a3.
SCORING
- Input 3 3 3: N ≤ 40 N \le 40 N≤40
- Input 4 4 4: N ≤ 80 N \le 80 N≤80
- Inputs 5 − 7 5-7 5−7: N ≤ 200 N \le 200 N≤200
- Inputs 8-16: No additional constraints.
二分查找 前缀和 线段树(思路过于复杂,太难)
任意两个区间[l1,r1]和[l2,r2],l1<=l2,l1<=r1l2<=r2。
情况一:两个区间无交叉。即r1 < l2。 ⟺ \iff ⟺ [l1,r1]之和等于[l2,r2]之和。
情况二:两个区间有包括关系。如:l1 <= l2 <= r2 <=l2, ⟺ \iff ⟺ a,区间[l1,l2]和[r2,l2]之和为0。b,或一个区间位0,令外一个区间不存在。由于本题所有区间和不存在,故只能是情况a。
情况三:两个区间交叉。 ⟺ \iff ⟺ [l1,l2]之和等于[r1,r2]。
情况三和情况一等效。
情况一和情况三,可以分成a,修改[l1,r1];b,修改[l2,r2]。
,x=区间2的和-区间1的和。将a[l2...r2]任意元素减少x,就相等了。
线段树[i]记录 修改a[i]可以让两个区间相等的最少修改量。
两层循环l2,r2
有序集合s记录所有区间[l1,r1]的前缀和。r1 < l2。
sum = preSum[r2+1]-preSum[l2]。
auto it = s.lower(sum)
x = min(it-sum,sum- (--it))
l2,r2\]的最小值修改为x。
**时间复杂度**:O(nnlog(nn))
### 关于树状数组
最大值树状数组,我只有单点修改的模板,所以无法使用树状数组。
### 未完成代码
```cpp
#include
j从0到大枚举v[j]
p1记录上一个包括a[i]的v[j1].区间和,默认值-1e18
p0记录上一个包括不a[i]的v[j1].区间和,默认值-1e18
如果v[j]包括a[i],则ans = min(abs(v[i]区间和-p0)
如果v[j]不包括a[i],则ans = min(abs(v[i]区间和-p1)
代码
cpp
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include <bitset>
using namespace std;
template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
in >> pr.first >> pr.second;
return in;
}
template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
return in;
}
template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
return in;
}
template<class T = int>
vector<T> Read() {
int n;
scanf("%d", &n);
vector<T> ret(n);
for(int i=0;i < n ;i++) {
cin >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
class Solution {
public:
vector<long long> Ans(vector<long long>& a) {
const int N = a.size();
vector<long long> preSum = { 0 };
for (const auto& ii : a) {
preSum.emplace_back(ii + preSum.back());
}
vector<tuple<long long, int, int>> v;
for (int left = 0; left < N; left++) {
for (int r = left; r < N; r++) {
v.emplace_back(preSum[r + 1] - preSum[left], left, r);
}
}
sort(v.begin(), v.end());
vector<long long> ans(N,LLONG_MAX/2);
for (int i = 0; i < N; i++) {
long long pre0 = -1e18;
auto pre1 = pre0;
for (const auto& [sum, left, r] : v) {
if ((left <= i) && (i <= r)) {
ans[i] = min(ans[i], sum - pre0);
pre1 = sum;
}
else {
ans[i] = min(ans[i], sum - pre1);
pre0 = sum;
}
}
}
return ans;
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
int n;
cin >> n;
auto c = Read<long long>(n);
auto res = Solution().Ans(c);
#ifdef _DEBUG
//printf("K=%d", K);
//Out(b, "b=");
//Out(c, "c=");
#endif // DEBUG
for (const auto& i : res) {
printf("%lld\r\n",i);
}
return 0;
}
单元测试
cpp
vector<long long> a;
TEST_METHOD(TestMethod11)
{
a = { 2,-3};
auto res = Solution().Ans(a);
AssertEx({ 2,3 }, res);
}
TEST_METHOD(TestMethod12)
{
a = { 3,-10,4 };
auto res = Solution().Ans(a);
AssertEx({ 1,6,1 }, res);
}
TEST_METHOD(TestMethod13)
{
a = { (long long)1e15,(long long)1e15 };
auto res = Solution().Ans(a);
AssertEx({ 0,0 }, res);
}
TEST_METHOD(TestMethod14)
{
a = { (long long)-1e15,(long long)1e15-1 };
auto res = Solution().Ans(a);
AssertEx({ (long long)1e15,(long long)1e15-1 }, res);
}
TEST_METHOD(TestMethod15)
{
a = { 1001,2000 };
auto res = Solution().Ans(a);
AssertEx({ 999,999 }, res);
}
TEST_METHOD(TestMethod16)
{
a = { 1001,2000,4000 };
auto res = Solution().Ans(a);
AssertEx({ 999,999,999 }, res);
}
扩展阅读
| 我想对大家说的话 |
|---|
| 工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
| 学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
| 有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
| 闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
| 如果程序是一条龙,那算法就是他的是睛 |
| 失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。