见证者为见证而来,铭记者因铭记而生|

园龄:粉丝:关注:

[CF2043C] Sums on Segments 题解

我们先想全是 ±1 的。令区间内最小子段和为 mn,最大子段和为 mx,注意到 [mn,mx] 内的数全都能被凑出来。

  • 证明:我们在区间 [l,r] 内任意取一个子区间 [l,r]

    • 定义【扩展】为将一个区间左边或右边添加一个数。
    • 定义【收缩】为将一个区间左边或右边去掉一个数。

    我们发现所有 [l,r] 的子区间都能通过 [l,r]【扩展】或【收缩】得到。而对于【扩展】或【收缩】,操作前后的 sum 一定是连续的。于是,所有子区间的 sum 都是连续的。所谓【连续】,当然是从最小和连续到最大和。

[mn,mx] 内的数加入答案即可。

对于有特殊值的,类似分治的思想,劈两半算两遍,再管包含特殊值的区间。和一定是左半的后缀加特殊值加右半的前缀。同理,只会取到最小值到最大值的所有数。

排序,去重,输出即可。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int> 
#define all(v) v.begin(), v.end()
using namespace std;

//#define filename "xxx" 
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)


namespace Traveller {
	const int N = 2e5+2;
	
	int n, a[N];
	
	vector<int> ans;
	int sum[N];
	void work(int *a, int n) {
		int x = 0, y = 0;
		int mx = 0, mn = 0;	//初值的艺术
		int sum = 0;
		for(int i = 1; i <= n; ++i) {
			sum += a[i];
			mx = max(mx, sum - y);
			mn = min(mn, sum - x);
			x = max(x, sum);
			y = min(y, sum);
		}
		for(int i = mn; i <= mx; ++i) ans.push_back(i);
	}
	
	void main() {
		cin >> n;
		for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];
		
		int p = -1;
		for(int i = 1; i <= n; ++i)
			if(abs(a[i]) != 1) {
				p = i;
				break;
			}
		
		ans.clear();
		if(~p) {
			int mx = 0, mn = 0;
			int x = 0, y = 0;
			work(a, p-1);
			for(int i = p-1; i >= 0; --i)
				x = max(x, sum[p-1] - sum[i]), y = min(y, sum[p-1] - sum[i]);
			mx += x, mn += y;
			
			x = y = 0;
			work(a+p, n-p);
			for(int i = p; i <= n; ++i)
				x = max(x, sum[i] - sum[p]), y = min(y, sum[i] - sum[p]);
			mx += x, mn += y;
			
			for(int i = mn; i <= mx; ++i) ans.push_back(i + a[p]);
		}
		else work(a, n);
		
		sort(all(ans));
		ans.erase(unique(all(ans)), ans.end());
		printf("%d\n", (int)ans.size());
		for(int ele : ans) printf("%d ", ele);
		puts("");
	}
}

signed main() {
	#ifdef filename
		FileOperations();
	#endif
	
	int _;
	cin >> _;
	while(_--) Traveller::main();
	return 0;
}


posted @   wfc284  阅读(43)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起