您的位置:首页 > 其它

归并模板& P1908 逆序对

2016-12-15 13:25 253 查看
写法1,先开一个新的数组赋值。

#include<iostream>
#include<cstdio>
using namespace std;
int n,a[1001],c[1001];
void merge(int l,int r)
{
if(l>=r) return;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
for(int i=l;i<=r;i++) c[i]=a[i];
//c[l...mid],c[mid+1,r]
int i=l,j=mid+1;
for(int k=l;k<=r;k++)//a[k]要重新赋值
{
if(i>mid) a[k]=c[j],j++;
else if(j>r) a[k]=c[i],i++;
else if(c[i]<c[j])
a[k]=c[i],i++;
else a[k]=c[j],j++;
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
merge(1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}


写法2,后开一个新的数组赋值。

Once Self

#include<iostream>
#include<cstdio>
using namespace std;
int a[1001],c[1001];
void merge(int l,int r)
{
if(l>=r) return;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid && j<=r)
{
if(a[i]<a[j])
c[k++]=a[i],i++;
else

4000
c[k++]=a[j],j++;
}
while(i>mid && k<=r)
c[k++]=a[j],j++;
while(j>r && k<=r)
c[k++]=a[i],i++;
for(int k=l;k<=r;k++) a[k]=c[k];//c[1] c[2] c[3] c[4] c[5]
}
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
merge(1,n);
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
}


题目描述

猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai > aj且i < j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

输入输出格式

输入格式:

第一行,一个数n,表示序列中有n个数。

第二行n个数,表示给定的序列。

输出格式:

给定序列中逆序对的数目。

输入输出样例

输入样例#1:

6

5 4 2 6 3 1

输出样例#1:

11

/*6

12 3 1 2 45 3

out 7*/

说明

对于50%的数据,n≤2500

对于100%的数据,n≤40000。

2 6 7 8    1 3 4 5//<-正着想很麻烦,倒着想很简单
i          j j j


#include<iostream>
#include<cstdio>
using namespace std;
int n,a[40005],c[40005],cnt;
void merge(int l,int r)
{
if(l>=r) return;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
for(int i=l;i<=r;i++) c[i]=a[i];
//c[l...mid],c[mid+1,r]
int i=l,j=mid+1,t=0;
for(int k=l;k<=r;k++)//
{
if(i>mid) a[k]=c[j],j++;
else if(j>r)
a[k]=c[i],i++;
else if(c[i]>c[j])
a[k]=c[j],j++,cnt+=mid-i+1;//注意这的写法及顺序 (开始是相反的写法,很麻烦)
else a[k]=c[i],i++;
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
merge(1,n);
cout<<cnt<<endl;
}


#include<iostream>
#include<cstdio>
using namespace std;
int a[40005],c[40005],ans;
void merge(int l,int r)
{
if(l>=r) return;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid && j<=r)
{
if(a[i]>a[j])
{
ans+=j-k;//或者mid-i+1
c[k++]=a[j],j++;
}
else
c[k++]=a[i],i++;
}
while(i>mid && k<=r )
c[k++]=a[j],j++;
while(j>r && k<=r )
c[k++]=a[i],i++;
for(int k=l;k<=r;k++) a[k]=c[k];//c[1] c[2] c[3] c[4] c[5]
}
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
merge(1,n);
cout<<ans<<endl;
}


树状数组求逆序对

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,a[1005],b[1005],c[1005],f[1005],res;//*****
void add(int x,int y)
{
while(x<=n)
{
f[x]+=y;
x+=x&-x;//110+10->1000  0101+1->0110
}
}
int query(int x)//查询前缀和
{
int sum=0;
while(x)
{
sum+=f[x];
x-=x&-x;
}
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);b[i]=a[i];
}
sort(b+1,b+n+1);
int u=unique(b+1,b+n+1)-(b+1);//去重
for(int i=1;i<=n;i++)
c[i]=lower_bound(b+1,b+n+1,a[i])-b;//a[i]这个数在原序列中排第几

//  for(int i=1;i<=n;i++)
//      cout<<c[i]<<" ";
//      cout<<endl;

//a[] 3 5 1 4 3 1-->9
//c[] 2 4 1 3 2 1
//    1 2 3 4
//4进来时,求前缀和,那么3 5 1被加1,则前缀和是3 和5 组成的和

//然后读入一个,查询一下前缀和
for(int i=1;i<=n;i++)
{
//      cout<<"Q: "<<query(c[i])<<endl;
res+=(i-1)-query(c[i]);
add(c[i],1);
}
cout<<res<<endl;
}
/*对于相同的数,比如1的前面有个1,但是它在算前面比它小的数时,确实0
因此,在树状数组中应该包含它自己,将先add再query,改成先query再add,且query时要包含自己*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: