牛客多校第五场-D-inv
链接:https://www.nowcoder.com/acm/contest/143/D
来源:牛客网
题目描述
Kanade has an even number n and a permutation b of all of the even numbers in [1,n]
Let a denote an array [1,3,5....n-1] , now you need to find a permutation of [1,n] satisfy both a and b are subsequence of it and minimize the number of inverse pair of it.
输入描述:
The first line has a positive even integer n
The second line has n/2 positive even integers b[i]
输出描述:
Output the number of inverse pair of the permutation you find.
备注:
1≤ n≤ 2e5
题意就是给你1-n之间所有偶数的一个排列,让你把奇数插入进去,使得生成的数列的逆序数最少。 为了使得逆序数最少,所有的奇数肯定是有序插入的,因此插入的位置肯定也是递增的。
对每个奇数找到插入之后产生逆序数最少的位置插入即可。 考虑用c[i]表示将当前奇数 2k+1 插入第i个位置时,产生的逆序数。 那么对于 2(k+1) +1 来说,c数组的变化其实是非常小的。 对于所有在 2(k+1) 这个数字之前的位置来说,放2(k+1)+1比放2k+1会多一个逆序数,而在它之后的位置会少一个。 因此用线段树维护c数组,每次选择逆序数最少的位置放即可。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+50; int n,m; int c[N],mn[N*4],lazy[N*4],t[N*4],b[N],pos[N]; ll ans; int lowbit(int x) { return x&(-x); } void add(int x) { for (int i=x;i<=n;i+=lowbit(i)) t[i]++; } int sum(int x) { int ret=0; for (int i=x;i>=1;i-=lowbit(i)) ret+=t[i]; return ret; } void PushUp(int s) { mn[s]=min(mn[s<<1],mn[s<<1|1]); } void PushDown(int s,int lenl,int lenr) { if (lazy[s]) { mn[s<<1]+=lazy[s]; mn[s<<1|1]+=lazy[s]; lazy[s<<1]+=lazy[s]; lazy[s<<1|1]+=lazy[s]; lazy[s]=0; } } void build(int s,int l,int r) { if (l==r) { mn[s]=c[l]; return ; } int mid=(l+r)>>1; build(s<<1,l,mid); build(s<<1|1,mid+1,r); PushUp(s); } void Updata(int s,int l,int r,int L,int R,int val) { if (L<=l&&r<=R) { mn[s]+=val; lazy[s]+=val; return ; } int mid=(l+r)>>1; PushDown(s,mid-l+1,r-mid); if (L<=mid) Updata(s<<1,l,mid,L,R,val); if (R>mid) Updata(s<<1|1,mid+1,r,L,R,val); PushUp(s); } int main() { scanf("%d",&n); int m=n/2; for (int i=1;i<=m;i++) { scanf("%d",&b[i]); pos[b[i]]=i; add(b[i]); ans+=i-sum(b[i]); } m++; for (int i=1;i<=m+1;i++) c[i]=i-1; build(1,1,m); for (int i=3;i<=n;i+=2) { Updata(1,1,m,1,pos[i-1],1); Updata(1,1,m,pos[i-1]+1,m,-1); ans+=mn[1]; } printf("%lld\n",ans); return 0; }