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\n",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\n",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\n",ans*min(x,y)); 64 } 65 return 0; 66 }
就这样吧,溜了。
啊啊啊啊,cf又掉分了༼༎ຶᴗ༎ຶ༽