[ARC178C] Sum of Abs 2 题解

首先想到能不能用差分搞搞,但是给自己绕进去了 /kel

我们不妨给 \(\{b_L\}\) 定个不降的序(如果打在数轴上,显然序和答案无关),于是可以拿掉绝对值。
注意到这个和式(记其结果为 \(x\) )中每个 \(b_i\) 的贡献系数 \(c_i = 2i - L - 1\),于是有:

\[x = \sum_{i = 1}^{L}b_ic_i \]

直接做不好处理最大值。\(\{b_n\}\) 有序,想到 Abel 变换(记 \(b_0=0,s_i = \sum_{j = i}^{L} c_j,d_i = b_i - b_{i-1}\)
):

\[\begin{aligned} x & = \sum_{i = 1}^{L}(b_i-b_{i-1})\sum_{j = i}^{L}c_j \\ & = \sum_{i = 1}^{L} d_is_i \end{aligned} \]

答案等价于最小化 \(\sum d_i\)
显然 \(d_i\ge0\),且可以证明(打表\(s_i \ge 0\),于是就可以把上面的式子看做背包的过程,跑一遍背包即可。

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

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

namespace Traveller {
	const int N = 2e5+2;
	
	int n, L;
	int sum[N], f[N];
	
	void main() {
		cin >> n >> L;
		for(int i = L; i >= 1; --i) sum[i] = sum[i+1] + 2*i - L - 1;
		memset(f, 0x3f, sizeof(f));
		f[0] = 0;
		for(int i = 1; i <= L; ++i)
			for(int j = sum[i]; j <= 2e5; ++j)	//完全背包
				f[j] = min(f[j], f[j - sum[i]] + 1);
		for(int i = 1, a; i <= n; ++i) {
			scanf("%lld ", &a);
			printf("%lld\n", f[a] > 1e9 ? -1 : f[a]);
		}
	}
}

signed main() {
#ifdef filename
	FileOperations();
#endif
	
	signed _ = 1;
#ifdef multi_cases
	scanf("%d", &_);
#endif
	while(_--) Traveller::main();
	return 0;
}

关于时间复杂度:
记值域为 \(V\)
我的代码中双重循环看起来什么没加,是 \(O(VL)\) 的,但是注意到 sum 数组增速很快,是平方级别的,也就是说他会在 \(O(\sqrt{V})\) 次就超出 \(2 \times 10^5\),不进行二重循环。
于是复杂度就是 \(O(V \sqrt{V})\),可能带点常数。

posted @ 2025-01-22 23:38  Water_M  阅读(13)  评论(0)    收藏  举报