bzoj4989 [Usaco2017 Feb]Why Did the Cow Cross the Road(树状数组求逆序对个数)

来源:互联网 发布:中文数据库有哪些 编辑:程序博客网 时间:2024/06/12 00:32

首先若a,b线段交叉且A[a]< A[b],则B[a]>B[b],若我们给A序列强制从小到大的标号,转换B序列保证符合原题。则线段交叉的对数,就是B序列中逆序对的个数。我们可以用树状数组nlogn求出。然后考虑循环移位,现在只考虑对B序列做循环移位(A序列同理,反过来做即可。),实质上就是对转换后的B序列做循环移位,我们每次只把最后一位挪到最前面,挪n-1次即可得到所有循环移位后的结果。考虑把最后一位x挪到第一位,对逆序对个数的影响是什么。因为操作之后x在第一位,所以所有比x小的都在他后面,构成了新的x-1个逆序对。原来比x大的现在都不再和x构成逆序对,所以少了(n-x)个以前的逆序对。而其他的位置没有变化。因此操作过后逆序对数的变化为x-1-(n-x)。这样我们只需用树状数组求出第一次的逆序对个数,以后的逆序对个数都可以O(1)得到,我们记录最小值即可。
tips:转A和转B得到的序列是不同的,必须做两次。

#include <cstdio>#include <cstring>#define N 100010#define ll long longinline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}inline ll min(ll x,ll y){return x<y?x:y;}int n,a[N],b[N],c[N];ll ans=0;inline int lowbit(int x){return x&(-x);}inline void insert(int x){    for(;x<=n;x+=lowbit(x)) c[x]+=1;}inline ll query(int x){    ll res=0;    for(;x>0;x-=lowbit(x)) res+=c[x];    return res;}int main(){//  freopen("a.in","r",stdin);    n=read();    for(int i=1;i<=n;++i){        int x=read();b[x]=i;    }    for(int i=1;i<=n;++i){int x=read();a[i]=b[x];}    ll res=0;    for(int i=n;i>=1;--i){        res+=query(a[i]);insert(a[i]);    }    ans=res;    for(int i=n;i>=2;--i) res+=a[i]-1-(n-a[i]),ans=min(ans,res);    for(int i=1;i<=n;++i) b[a[i]]=i;    res=0;memset(c,0,sizeof(c));//注意清零     for(int i=n;i>=1;--i){        res+=query(b[i]);insert(b[i]);    }    ans=min(ans,res);    for(int i=n;i>=2;--i) res+=b[i]-1-(n-b[i]),ans=min(ans,res);    printf("%lld\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击