HDU 6318.Swaps and Inversions-求逆序对-线段树 or 归并排序 or 离散化+树状数组 (2018 Multi-University Training Contest 2 1010)

6318.Swaps and Inversions

这个题就是找逆序对,然后逆序对数*min(x,y)就可以了。

官方题解:注意到逆序对=交换相邻需要交换的次数,那么输出 逆序对个数 即可。

求逆序对有4种操作,线段树 、BIT、归并排序、树状数组。

我敲了线段树、归并排序和树状数组版的。

关于这几种方法求逆序对,自行百度吧,懒了。。。

代码(线段树版-注意排序):

 1 //1010-找逆序对数-线段树求逆序对数
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<cstdlib>
 8 #include<queue>
 9 #include<stack>
10 using namespace std;
11 typedef long long ll;
12 const int inf=0x3f3f3f3f;
13 const double eps=1e-5;
14 const int maxn=1e5+10;
15 #define lson l,m,rt<<1
16 #define rson m+1,r,rt<<1|1
17 int sum[maxn<<2];
18 
19 void PushUp(int rt)
20 {
21     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
22 }
23 
24 void build(int l,int r,int rt)
25 {
26     sum[rt]=0;
27     if(l==r){
28         return ;
29     }
30 
31     int m=(l+r)>>1;
32     build(lson);
33     build(rson);
34     PushUp(rt);
35 }
36 
37 void update(int p,int l,int r,int rt)
38 {
39     if(l==r){
40         sum[rt]++;
41         return ;
42     }
43 
44     int m=(l+r)>>1;
45     if(p<=m)update(p,lson);
46     else update(p,rson);
47     PushUp(rt);
48 }
49 
50 ll query(int L,int R,int l,int r,int rt)
51 {
52     if(L<=l&&r<=R){
53         return sum[rt];
54     }
55     int m=(l+r)>>1;
56     ll ret=0;
57     if(L<=m) ret+=query(L,R,lson);
58     if(R> m) ret+=query(L,R,rson);
59     return ret;
60 }
61 
62 int a[maxn],b[maxn];
63 int main()
64 {
65     int n,x,y;
66     while(~scanf("%d%d%d",&n,&x,&y)){
67         build(1,n,1);
68         for(int i=1;i<=n;i++){
69             scanf("%d",&a[i]);
70             b[i]=a[i];
71         }
72         sort(b+1,b+n+1);
73         int len=unique(b+1,b+n+1)-b-1;
74         for(int i=1;i<=n;i++){
75             a[i]=upper_bound(b+1,b+len+1,a[i])-b-1;
76         }
77 
78         ll sum=0;
79         for(int i=1;i<=n;i++){
80             sum+=query(a[i]+1,n,1,n,1);
81             update(a[i],1,n,1);
82         }
83         printf("%lld
",sum*min(x,y));
84     }
85     return 0;
86 }

代码(归并排序版):

 1 //1010-6318-求逆序对数-归并排序
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<cstdlib>
 8 #include<cassert>
 9 using namespace std;
10 typedef long long ll;
11 const int maxn=1e5+10;
12 const int inf=0x3f3f3f3f;
13 
14 int a[maxn],tmp[maxn];
15 ll ans;
16 
17 void Merge(int l,int m,int r)
18 {
19     int i=l;
20     int j=m+1;
21     int k=l;
22     while(i<=m&&j<=r){
23         if(a[i]>a[j]){
24             tmp[k++]=a[j++];
25             ans+=m-i+1;
26         }
27         else{
28             tmp[k++]=a[i++];
29         }
30     }
31     while(i<=m) tmp[k++]=a[i++];
32     while(j<=r) tmp[k++]=a[j++];
33     for(int i=l;i<=r;i++)
34         a[i]=tmp[i];
35 }
36 
37 void Merge_sort(int l,int r)
38 {
39     if(l<r){
40         int m=(l+r)>>1;
41         Merge_sort(l,m);
42         Merge_sort(m+1,r);
43         Merge(l,m,r);
44     }
45 }
46 
47 int main()
48 {
49     int n,x,y;
50     while(~scanf("%d%d%d",&n,&x,&y)){
51         memset(a,0,sizeof(a));
52         memset(tmp,0,sizeof(tmp));
53         for(int i=1;i<=n;i++)
54             scanf("%d",&a[i]);
55         ans=0;
56         Merge_sort(1,n);
57         printf("%lld
",ans*min(x,y));
58     }
59 }

可以去看一下ACdreamer的博客。

代码(离散化+树状数组):

 1 //1010-6318-求逆序对-离散化+树状数组版
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<cstdlib>
 8 #include<queue>
 9 #include<cassert>
10 #include<map>
11 using namespace std;
12 typedef long long ll;
13 const int maxn=1e5+10;
14 
15 int tree[maxn];
16 int n;
17 
18 int lowbit(int x)
19 {
20     return x&(-x);
21 }
22 
23 void update(int x,int val)
24 {
25     for(int i=x;i<=n;i+=lowbit(i)){
26         tree[i]+=val;
27     }
28 }
29 
30 ll getsum(int x)
31 {
32     ll ans=0;
33     for(int i=x;i>0;i-=lowbit(i)){
34         ans+=tree[i];
35     }
36     return ans;
37 }
38 
39 int a[maxn],b[maxn];
40 map<int,int> mp;
41 
42 int main()
43 {
44     int x,y;
45     while(~scanf("%d%d%d",&n,&x,&y)){
46         for(int i=1;i<=n;i++){
47             scanf("%d",&a[i]);
48             b[i]=a[i];
49         }
50         sort(b+1,b+1+n);
51         int num=1;
52         mp.clear();
53         for(int i=1;i<=n;i++)
54             mp[b[i]]=num++;
55         for(int i=1;i<=n;i++)
56             a[i]=mp[a[i]];
57         memset(tree,0,sizeof(tree));
58         ll ans=0;
59         for(int i=n;i>0;i--){
60             ans+=getsum(a[i]-1);
61             update(a[i],1);
62         }
63         printf("%lld
",ans*min(x,y));
64     }
65     return 0;
66 }

就这样吧,溜了。

啊啊啊啊,cf又掉分了༼༎ຶᴗ༎ຶ༽

原文地址:https://www.cnblogs.com/ZERO-/p/9399958.html