赞
踩
题目链接:https://www.starrycoding.com/contest/3/E
小e发明了一种奇怪的数据结构——ET表,这一奇怪的数据结构有以下两种奇怪的操作:
为了测试ET表的性能,小e找来了一个长度为 n n n 数组 a a a,现在需要判断能否通过ET表的这两种操作将这个数组的每一个数都变成 0 0 0,以及最少的操作次数。
第一行为一个正整数 T T T ( 1 ≤ T ≤ 1 0 6 1 \le T \le 10^6 1≤T≤106 ),表示测试用例个数。
对于每个测试用例:
第一行为一个正整数 n n n ( 1 ≤ n ≤ 1 0 6 1 \le n \le 10^6 1≤n≤106 ),表示数组长度;
第二行包含 n n n 个正整数 a 1 … a n a_1 \ldots a_n a1…an ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106 )
数据保证 ∑ n ≤ 1 0 6 \sum{n} \le 10^6 ∑n≤106。
每个测试用例的输出一行:
4
3
1 2 1
3
2 3 2
5
19 1 9 8 10
6
1 1 4 5 1 4
2
3
4
-1
对于样例第二组数据 [ 2 , 3 , 2 ] [2, 3, 2] [2,3,2],
成功归零,共操作 3 3 3 次。
对于样例第三组数据 [ 19 , 1 , 9 , 8 , 10 ] [19, 1, 9, 8, 10] [19,1,9,8,10],
成功归零,共操作 4 4 4 次。
对于样例第四组数据,无论如何也无法将其归零。
其实所谓的ET表操作,其实就是对数组的某一长度的前、后缀进行区间减去某个数的操作,此时我们应该想到非常擅长进行区间操作的好东西——差分。
建立差分数组 d d d,对于数组 [ l , r ] [l,r] [l,r] 的修改就等效于对差分数组的 d l d_l dl 和 d r + 1 d_{r+1} dr+1 进行修改,此时的ET表操作就变成了:
且此时 d n + 1 d_{n+1} dn+1 对数组 a a a 不会有任何影响,所以对它的操作可以忽略,而我们的最终目的——将数组 a a a 归零也就等效于将 d 1 … d n d_1 \ldots d_n d1…dn 归零。所以在判断是否可行是,我们只需要计算差分数组中所有小于 0 0 0 的数的绝对值之和 s s s,将这个总和与 d 1 d_1 d1 进行比较,如果大于 d 1 d_1 d1 则说明无法完成归零。计算最少操作次数则贪心的只对 d 2 … d n d_2 \ldots d_n d2…dn 中每个非 0 0 0 的进行一次操作,最后特判一下进行了上述操作后 d 1 d_1 d1 是否已经归零,也就是 s s s 是否等于 d 1 d_1 d1 来确定是否还要进行一次操作使 d 1 d_1 d1 归零。
void solve() { int n; cin >> n; vector<int> a(n + 1); vector<int> d(n + 1, 0); for (int i = 1; i <= n; i++) { cin >> a[i]; d[i] = a[i] - a[i - 1]; // 差分 } int s = 0, ans = 0; for (int i = 2; i <= n; i++) { if (d[i] < 0) { s += abs(d[i]); // 对于差分数组中小于0的进行操作一, ans++; // 操作次数+1,并记录会对d[1]产生的影响 } else if (d[i] > 0) { ans++; // 对于大于0的进行一次操作二 } } if (s > d[1]) // d[1]不足以完成足够的操作一 { cout << -1 << endl; return; } if (s < d[1]) // 当前进行的操作一不足以将d[1]归零 { ans++; } cout << ans << endl; return; }
StarryCoding - 编程开发新手村,非常适合新手小白的一个网站,推荐给大家~
5月1日晚上还有一场入门教育赛,欢迎来玩:https://www.starrycoding.com/contest/5
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。