CSAcademy Beta Round #4 Swap Pairing

题目链接:https://csacademy.com/contest/arhiva/#task/swap_pairing/

大意是给2*n个包含n种数字,每种数字出现恰好2次的数列,每一步操作可以交换相邻的两个数字,问最少需要操作多少次,可以使得所有的同种数字都相邻。

 

我的做法是考虑不同的数对的数字在原来数列中的位置关系,有三大类,如果我们用[]和{}表示的话就是:

[]{}

[{]}

[{}]

这三种位置情况。

第一种情况对答案的贡献应当是0。

第二种情况对答案的贡献应当是1。

第三种情况对答案的贡献应当是2。

 

接下来问题就是如何统计。我的方法是先计算所有的pair对,

总共n种数字,那么数对的个数就是(n-1)*n/2。

接下来需要减去第一种情况的个数,再加上第三种情况的个数。

第一种情况的统计应当是比较简单的,第三种情况可以规约到求某个线段内部有多少线段的问题。

统计可以用BIT来维护。

 

代码如下:

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <string>
 5 #include <string.h>
 6 #include <stdio.h>
 7 #include <math.h>
 8 #include <queue>
 9 #include <stack>
10 #include <map>
11 #include <ctime>
12 #include <set>
13 using namespace std;
14 
15 const int N=123456;
16 int a[N];
17 map<int,int> le;
18 map<int,int> ri;
19 
20 pair<int,int> pos[N];
21 int v[N];
22 int lowbit(int x) {
23     return x & -x;
24 }
25 int get(int x) {
26     int ret=0;
27     while (x) {
28         ret+=v[x];
29         x-=lowbit(x);
30     }
31     return ret;
32 }
33 void add(int x,int add) {
34     while (x<N) {
35         v[x]+=add;
36         x+=lowbit(x);
37     }
38 }
39 int main () {
40     int n;
41     while (scanf("%d",&n)!=EOF) {
42         memset(v,0, sizeof(v));
43         le.clear();
44         ri.clear();
45         for (int i=1;i<=n;i++) {
46             scanf("%d",a+i);
47             if (le[a[i]]==0)
48                 le[a[i]]=i;
49             else ri[a[i]]=i;
50         }
51         int cnt=1;
52         for (map<int,int>::iterator it=le.begin();it!=le.end();it++) {
53             int key=it->first;
54             int val1=it->second;
55             int val2=ri[key];
56             pos[cnt].first=val1;
57             pos[cnt++].second=val2;
58         }
59         sort(pos+1,pos+cnt);
60         int tot=n/2;
61         long long ret=(tot-1)*1LL*tot/2LL;
62         for (int i=tot;i>=1;i--) {
63             int l=pos[i].first;
64             int r=pos[i].second;
65             ret+=get(r);
66             add(r,1);
67         }
68         memset(v,0,sizeof v);
69         for (int i=1;i<=tot;i++) {
70             int l=pos[i].first;
71             int r=pos[i].second;
72             ret-=get(l);
73             add(r,1);
74         }
75         cout<<ret<<endl;
76 
77     }
78 }
View Code

 

 

题解给了另一种做法,可以有一种最优解第一个数字不用移动,则接下来所有数字怎么移动都被固定了,中间仍然是用BIT来维护。

 

posted @ 2016-04-27 13:17  活在夢裡  阅读(238)  评论(0编辑  收藏  举报