【HOJ2430】【贪心+树状数组】 Counting the algorithms

As most of the ACMers, wy's next target is algorithms, too. wy is clever, so he can learn most of the algorithms quickly. After a short time, he has learned a lot. One day, mostleg asked him that how many he had learned. That was really a hard problem, so wy wanted to change to count other things to distract mostleg's attention. The following problem will tell you what wy counted.

Given 2N integers in a line, in which each integer in the range from 1 to N will appear exactly twice. You job is to choose one integer each time and erase the two of its appearances and get a mark calculated by the differece of there position. For example, if the first 3 is in position 86 and the second 3 is in position 88, you can get 2 marks if you choose to erase 3 at this time. You should notice that after one turn of erasing, integers' positions may change, that is, vacant positions (without integer) in front of non-vacant positions is not allowed.

Input

There are multiply test cases. Each test case contains two lines.

The first line: one integer N(1 <= N <= 100000).

The second line: 2N integers. You can assume that each integer in [1,N] will appear just twice.

Output

One line for each test case, the maximum mark you can get.

Sample Input

 

3

1 2 3 1 2 3

3

1 2 3 3 2 1

Sample Output

 

6

9

Hint

We can explain the second sample as this. First, erase 1, you get 6-1=5 marks. Then erase 2, you get 4-1=3 marks. You may notice that in the beginning, the two 2s are at positions 2 and 5, but at this time, they are at positions 1 and 4. At last erase 3, you get 2-1=1 marks. Therefore, in total you get 5+3+1=9 and that is the best strategy.

 

【分析】

比较水的一道题,根据题意可知,任何两个区间仅为相交或包含的关系。

相交无论先删除哪一个对结果都没有影响,包含当然要先删除外面的那一个,所以从后往前删不会有包含的关系。

具体用树状数组实现就可以了。

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <algorithm>

 4 #include <cstring>

 5 #include <vector>

 6 #include <utility>

 7 #include <iomanip>

 8 #include <string>

 9 #include <cmath>

10 #include <map>

11 

12 const int MAXN = 100000 * 2 + 10; 

13 using namespace std;

14 struct DATA{

15        int l, r; 

16 }num[MAXN * 2];

17 int data[MAXN * 2];

18 int C[MAXN * 2], cnt[MAXN * 2];

19 int n;

20 bool get[MAXN * 2];

21 

22 int lowbit(int x){return x&-x;}

23 void add(int x, int val){

24      while (x <= 2 * n){

25            C[x] += val;

26            x += lowbit(x);

27      }

28      return;

29 }

30 int sum(int x){

31     int cnt = 0;

32     while (x > 0){

33           cnt += C[x];

34           x -= lowbit(x);

35     }

36     return cnt;

37 }

38 void init(){

39      C[0] = 0;

40      for (int i = 1; i <= 2 * n; i++) C[i] = cnt[i] = 0;

41      for (int i = 1; i <= 2 * n; i++){

42          scanf("%d", &data[i]);

43          if (cnt[data[i]] == 0) {num[data[i]].l = i;cnt[data[i]]++;}

44          else num[data[i]].r = i;

45          add(i, 1);

46      }

47      long long Ans = 0;

48      memset(get, 0, sizeof(get));

49      for (int i = 2 * n; i >= 1; i--){

50          if (get[i] == 1) continue;

51          Ans += sum(i) - sum(num[data[i]].l); 

52          add(i, -1);

53          add(num[data[i]].l, -1);

54          get[i] = get[num[data[i]].l] = 0;

55      }

56      printf("%lld\n", Ans);

57 }

58 

59 int main(){

60      int T = 0; 

61      #ifdef LOCAL

62      freopen("data.txt", "r", stdin);

63      freopen("out.txt", "w", stdout); 

64      #endif 

65      while (scanf("%d", &n) != EOF){

66            init();

67      }

68      return 0;

69 }

70  
View Code

 

你可能感兴趣的:(algorithms)