AcWing 1215. 小朋友排队
作者:互联网
考察:树状数组 +贪心 or归并排序+贪心
思路:
首先一个定理:冒泡排序的交换次数 = 逆序对个数.证明: 冒泡排序每次交换减少一个逆序对,当最后逆序对数量 = 0,交换次数>=k. 又因为每次只能减少一个.那么必然可以取到k.对于某一个人i而言,i前面>hi有k个,后面<hi有t个.k+t就是i的交换次数最优解,而无需考虑是否相邻的问题.将每个人的k+t累加,和为逆序对数量*2,因为最优解的交换次数就是逆序对*2(一个逆序对对于两个人来说都+1).所以k+t就是i交换次数的最优解.
所以计算每个人的k+t即可,可以用归并排序或树状数组.
如果用归并,要记录每个人的交换前后位置差,不能用int数组记录第i个人交换次数,因为每人的id都在变化.
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int N = 100010; 7 int n; 8 LL ans; 9 struct SS{ 10 int h,id,cnt; 11 }ss[N],b[N]; 12 void merge(int l,int r) 13 { 14 if(l==r) return; 15 int mid = l+r>>1; 16 merge(l,mid); merge(mid+1,r); 17 int i = l,j = mid+1,k= 0; 18 while(i<=mid&&j<=r) 19 { 20 if(ss[i].h<=ss[j].h) b[k++] = ss[i++]; 21 else 22 b[k++] = ss[j++]; 23 } 24 while(i<=mid) b[k++] = ss[i++]; 25 while(j<=r) b[k++] = ss[j++]; 26 for(int i=l;i<=r;i++) 27 { 28 ss[i] =b[i-l]; 29 ss[i].cnt+=abs(ss[i].id-i); 30 ss[i].id = i; 31 } 32 } 33 int main() 34 { 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++) 37 { 38 scanf("%d",&ss[i].h); 39 ss[i].id = i; 40 } 41 merge(1,n); 42 for(int i=1;i<=n;i++) ans +=(LL)(1+ss[i].cnt)*ss[i].cnt/2; 43 printf("%lld\n",ans); 44 return 0; 45 }归并
树状数组,记录每个人前面>hi的有几个,答案是summax-sumhi.树状数组只能求前面<=hi的.所以可以利用前缀和.
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int N = 100010,M = 1000010; 7 int n,h[N],tr[M],cnt[N]; 8 LL ans; 9 int lowbit(int x) 10 { 11 return x&-x; 12 } 13 void add(int idx,int x) 14 { 15 for(int i=idx;i<=M-10;i+=lowbit(i)) tr[i]+=x; 16 } 17 int query(int x) 18 { 19 int res= 0; 20 for(int i=x;i;i-=lowbit(i)) res+=tr[i]; 21 return res; 22 } 23 int main() 24 { 25 scanf("%d",&n); 26 for(int i=1;i<=n;i++) scanf("%d",&h[i]); 27 for(int i=1;i<=n;i++) 28 { 29 cnt[i]+=query(M-10)-query(h[i]); 30 add(h[i],1); 31 } 32 memset(tr,0,sizeof tr); 33 for(int i=n;i>=1;i--) 34 { 35 cnt[i]+=query(h[i]-1); 36 add(h[i],1); 37 } 38 for(int i=1;i<=n;i++) ans+=(LL)cnt[i]*(cnt[i]+1)/2; 39 printf("%lld\n",ans); 40 return 0; 41 }树状数组
标签:1215,int,树状,交换,数组,逆序,小朋友,include,AcWing 来源: https://www.cnblogs.com/newblg/p/14478184.html