这道题目是求逆序数的。要得到答案,需要利用一个结论,如果是0到n-1 的排列,那么如果第一个数放到最后,这与这个数列,逆序数减少a[i],增加n-a[i]-1;
隔了几天之后,再做这道题目,发现有点生疏了。
在题目中的数字是从 0--n-1的。因此在初始化的时候要 build( 0,n-1 ,1)
在query 函数里,是查询a[i]到n-1 一段区间里面的逆序数。
time 62ms
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N=5005;
int sum[N<<2];
int a[N];
void push_up(int rt)
{ sum[rt]=sum[rt<<1]+sum[rt<<1|1] ; }
void build(int l,int r,int rt)
{
sum[rt]=0;
if(l==r) return ;
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
}
void updata(int l,int r,int rt,int p)
{
if(l==r)
{ sum[rt]++;
return ;
}
int m=(l+r)>>1;
if(p<=m)
updata(l,m,rt<<1,p);
else
updata(m+1,r,rt<<1|1,p);
push_up(rt);
}
int query(int l,int r,int rt,int s,int t)
{
if(s<=l&& t>=r)
{
return sum[rt];
}
int m=(l+r)>>1;
int ret=0;
if(s<=m)
ret+=query(l,m,rt<<1,s,t);
if(t>m)
ret+=query(m+1,r,rt<<1|1,s,t);
return ret;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int ans=0;
build(0,n-1,1);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
ans+=query(0,n-1,1,a[i],n-1);
updata( 0,n-1,1,a[i] );
}
int ret=ans;
for(int i=0;i<n;i++)
{
ans=(ans-a[i] )+ (n-a[i]-1) ;
ret=min(ret,ans );
}
printf("%d\n",ret);
}
}
在使用zkw 线段树的做法的时候,时间减少到了46ms;
贴上代码
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <memory.h>
using namespace std;
const int N=5005;
int T[N<<2];
int M;
void push_up(int n)
{
T[n]=T[n<<1]+T[n<<1|1];
}
void updata(int n)
{
for(T[n+=M]+=1,n>>=1;n;n>>=1)
push_up(n);
}
int query(int s,int t)
{
int ans=0;
for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1)
{
if(~s&1) ans+=T[s^1];
if( t&1) ans+=T[t^1];
}
return ans;
}
int a[N];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(M=1;M<=n+1;M<<=1);
int sum=0;
memset(T,0,sizeof(T));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
a[i]++; <span style="font-family: 'Courier New'; white-space: pre-wrap; color: rgb(0, 128, 0); line-height: 1.5 !important;">//</span><span style="font-family: 'Courier New'; white-space: pre-wrap; color: rgb(0, 128, 0); line-height: 1.5 !important;">注意后面add的时候不能在0位置上add</span>
if(a[i]!=n)
sum+=query(a[i]+1,n);
updata(a[i]);
}
int ret=sum;
for(int i=0;i<n;i++)
{
sum=sum+(n-a[i])-(a[i]-1);
ret=min(ret,sum);
}
printf("%d\n",ret);
}
}