[HOJ - 2430] Counting the algorithms (树状数组+贪心)

it2022-05-05  151

链接

http://acm.hit.edu.cn/problemset/2430

题意

给你一个由 1 − n   , n 1-n\ ,n 1n ,n个数组成的长度为 2 n 2n 2n的整数序列,其中 1 − n 1-n 1n每个数出现两次,现在定义一个数产生的一个 v a l u e value value为它出现的两个位置的差值,如 x x x出现在 a 、 b a、b ab两个位置,那么 v a l u e = b − a ( b > a ) value=b-a(b>a) value=ba(b>a),之后你需要从序列中删除掉这两个数,并且你需要把序列整合即需要填充空位,每次求值之后你都需要这样进行整合,现在需要你求所有数的最大 v a l u e value value和;

分析

  对于一个序列1、2、2、1,那么我们肯定不能先计算2,因为2计算之后会导致1的间距变小,所以我们需要先计算外面的,对于1、3、2、1、3、2,我们也肯定不能计算3,因为3计算后会导致1与2的结果都变小,虽然先计算1或者2也会变小,但是它只会减少1,多举几个例子发现需要贪心的从外往里进行计算(从右往左或从左往右都可以);   考虑每个数产生的值可以转换为区间和,代表两个位置之间整数的个数,每删除一个数,就在它的两个位置插入一个-1;   之后我们使用树状数组,树状数组的下标代表位置,开始的时候我们需要在每个位置都插入一个1,因为序列还没有进行删除操作;对于同一个数我们记录下它的两个位置,然后我们便开始从右往左或者从左往右遍历,遇到一个数我们就计算它产生的值即 s u m ( b ) − s u m ( a ) ( b > a ) sum(b)-sum(a)(b>a) sum(b)sum(a)(b>a),其中a、b即是该数出现的两个位置,之后我们在树状数组的这两个位置插入-1,表明该位置数已被删除,然后将该数字标记说明已经计算了,累加所有数的结果即可;

代码

#include <functional> #include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <queue> #include <stack> #include <cmath> #include <set> #include <map> #define INF 0x7f7f7f7f #define MAXN 100005 #define N 200005 #define P 2 #define MOD 99991 typedef long long ll; namespace fastIO { //#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) //char buf[(1 << 22)], *p1 = buf, *p2 = buf; inline int read() { char c = getchar(); int x = 0, f = 1; while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } } using namespace fastIO; using namespace std; int n, c[2 * MAXN], r[MAXN], a[2 * MAXN]; void insert(int x, int val) { for (int i = x; i <=2 * n; i += i & -i) c[i] += val; } int sum(int x) { if (x <= 0) return 0; int res = 0; for (int i = x; i > 0; i -= i & -i) res += c[i]; return res; } int main() { while (cin >> n) { memset(c, 0, sizeof(c)); for (int i = 1; i <= 2 * n; i++) { cin >> a[i]; insert(i, 1); r[a[i]] = i; } int res = 0; for (int i = 1; i <= 2 * n; i++) { int t = r[a[i]]; if (!t)continue; res += (sum(t) - sum(i)); insert(t, -1); insert(i, -1); r[a[i]] = 0; } cout << res << endl; } }

最新回复(0)