P1966 火柴排队
这题贪心显然,即将两序列中第k大的数的位置保持一致,证明略;
树状数组求逆序对啦
浅谈树状数组求逆序对及离散化的几种方式及应用
方法:从前向后每次将数插入到bit(树状数组)中,求其前缀和(在它之前插入且比它小的数),那么用i(当前插入的数的总数)- 前缀和就是其(以c[i]为结尾)逆序对对数
这个题需要将一个序列按照另一个序列排序,因为只需要移动一个序列,sort排序就有了第k小的数的下标
$c[a[i].id]=b[i].id$
第i小的数在a中的位置就是b中第i小的数应放的位置,相当于以第一个数列为关键字排序第二个数列
#include<bits/stdc++.h> #define N 1010100 using namespace std; const int mod=99999997; int n,c[N],bit[N],ans; struct node{ int x,id; }a[N],b[N]; bool cmp(node A,node B){ return A.x<B.x; } int lowbit(int k){ return k&(-k); } void add(int x,int w){ while(x<=n){ bit[x]+=w; bit[x]%=mod; x+=lowbit(x); } } int sum(int x){ int res=0; while(x){ res+=bit[x]; x-=lowbit(x); res%=mod; } return res%mod; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].id=i; for(int i=1;i<=n;i++) scanf("%d",&b[i].x),b[i].id=i; sort(a+1,a+1+n,cmp); sort(b+1,b+1+n,cmp); for(int i=1;i<=n;i++) c[a[i].id]=b[i].id; for(int i=1;i<=n;i++){ add(c[i],1); ans=(ans+(i-sum(c[i])))%mod; } printf("%d ",ans); return 0; }
P1774 最接近神的人_NOI导刊2010提高(02)
同样的离散化,只不过是从后向前插入,那么其前缀和就是逆序数。
#include<bits/stdc++.h> #define N 500005 #define ll long long using namespace std; int n,h[N],c[N]; ll ans; struct node{ int y;ll x; bool operator<(const node A)const { return x==A.x ? y<A.y :x<A.x; } }e[N]; void update(int k,int x){ for(;k<=n;k+=k&-k) c[k]+=x; } ll query(int k){ ll an=0; for(;k;k-=k&-k) an+=c[k]; return an; } int main() { cin>>n; for(int i=1;i<=n;i++) scanf("%lld",&e[e[i].y=i].x); sort(e+1,e+1+n); for(int i=n;i;i--){ ans+=query(e[i].y-1); update(e[i].y,1); }cout<<ans; // printf("%lld",ans); return 0; }