题目描述
破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……
仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF不会……只好又找到了你,并答应事成之后与你三七分……
输入输出格式
输入格式:
第一行为一个整数n,表示序列长度
第二行为n个整数,表示序列中每个元素。
输出格式:
一个整数ans,即最少操作次数。
输入输出样例
输入样例#1:
4 2 8 0 3
输出样例#1:
3 样例说明:开始序列为2 8 0 3,目标序列为0 2 3 8,可进行三次操作的目标序列: 1.Swap (8,0):2 0 8 3 2.Swap (2,0):0 2 8 3 3.Swap (8,3):0 2 3 8
说明
对于30%的数据1≤n≤10^4。
对于100%的数据1≤n≤5*10^5;
-maxlongint≤A[i]≤maxlongint。
这题用归并排序可以水过。
但是我用了树状数组+离散化+二分
首先,树状数组中存的是小于等于当前位置的数的个数
我们先把原来的数组排序,然后每次利用二分的方式求出待求的数在排好序的序列中出现的位置
这是因为是按顺序枚举,所以我们每次默认有i个数比正在枚举的数大,那么我们用树状数组找出小于当前数的个数即可
最后一减就是答案
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define lli long long int 7 using namespace std; 8 const lli MAXN=2000001; 9 lli lowbit(lli p) 10 { 11 return p&-p; 12 } 13 void read(lli &n) 14 { 15 char c='+';lli x=0;bool flag=0; 16 while(c<'0'||c>'9') 17 {c=getchar();if(c=='-')flag=1;} 18 while(c>='0'&&c<='9') 19 {x=x*10+(c-48);c=getchar();} 20 flag==1?n=-x:n=x; 21 } 22 lli a[MAXN]; 23 lli tree[MAXN],mp[MAXN]; 24 lli n; 25 lli query(lli p) 26 { 27 lli tot=0; 28 while(p) 29 { 30 tot+=tree[p]; 31 p=p-lowbit(p); 32 } 33 return tot; 34 } 35 void add(lli p) 36 { 37 while(p<=MAXN/2) 38 { 39 tree[p]++; 40 p+=lowbit(p); 41 } 42 } 43 int erfen(int num) 44 { 45 int l=1,r=n; 46 while(l<r) 47 { 48 int mid=(l+r)>>1; 49 if(mp[mid]==num) 50 return mid; 51 if(mp[mid]>num) 52 r=mid-1; 53 if(mp[mid]<num) 54 l=mid+1; 55 } 56 return l; 57 } 58 int main() 59 { 60 // memset(tree,0,sizeof(tree)); 61 read(n); 62 lli ans=0; 63 for(lli i=1;i<=n;i++) 64 { 65 read(a[i]); 66 mp[i]=a[i]; 67 } 68 sort(mp+1,mp+n+1); 69 for(int i=1;i<=n;i++) 70 { 71 int p=erfen(a[i]); 72 add(p); 73 ans+=i-query(p); 74 } 75 printf("%lld",ans); 76 return 0; 77 }