https://vjudge.net/problem/HDU-2689
给定一个 1-n的全排列,问逆序数是多少。
每次更新,然后统计前面比i小的数。
或者用分治的思想。每次折半判断
逆序数总共分成三种情况
1
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
/* 方法。
判断里面有几个大于i的数.
*/
const int maxn=2000;
int a[maxn];
int lowbit(int a){
return a&(-a);
}
int t;
void update(int x,int b){
for(int i=x;i<=t;i+=lowbit(i)){
a[i]++;//单点更新
}
}
int query(int x){
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=a[i];//求和
return sum;
}
int main()
{
int x;
while(~scanf("%d",&t)){
memset(a,0,sizeof(a));
int all=0;
for(int i=0;i<t;i++){
scanf("%d",&x);
update(x,1);
all+=(i+1-query(x));
//cout<<all<<endl;
}
printf("%d\n",all);
}
return 0;
}
分治
#include <bits/stdc++.h>
using namespace std;
/*或者用分治。
这里有一个对分治法的理解,那就是在对子问题排序之后,
计算 交叉的情况时,默认子问题已经排序过了,因为其逆序数已经计算。
*/
typedef long long ll;
vector<int>v;
long long solve(int l,int r,vector<int>&a){
int len=a.size();
if(len<=1) return 0;
ll cnt=0;
vector<int>f(a.begin(),a.begin()+len/2);
vector<int>s(len/2+a.begin(),a.end());
cnt+=solve(l,len/2,f);
cnt+=solve(len/2,r,s);
//cout<<cnt<<"!!"<<endl;
int ps=0;
int pf=0;
int zb=0;
while(!(ps==s.size()&&pf==f.size())){
if((ps==s.size()||f[pf]<=s[ps])&&pf<f.size())
{a[zb++]=f[pf++];
//cout<<l<<" "<<r<<f[pf-1]<<endl;
}
else{
cnt+=1ll*(len/2-pf);
a[zb++]=s[ps++];
//cout<<l<<" "<<r<<s[ps-1]<<endl;
}
}
return cnt;
}
int main()
{ int t;
int k;
while(~scanf("%d",&t)){
v.clear();
v.resize(t);
for(int i=0;i<t;i++){
scanf("%d",&k);
v.push_back(k);
}
printf("%lld\n",solve(0,v.size(),v));
//for(int i=0;i<v.size();i++)
//cout<<v[i]<<endl;
}
return 0;
}