【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

 

转载于:https://www.cnblogs.com/hoskey/p/4319874.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值