SSL_1498&&P1908【逆序对】

逆序对

题目

P1908
备注:SSLOJ带多测,n<=250000,值小于100


解析

本题是裸的逆序对,关键在于怎么做
显然可以使用归并排序或树状数组+离散化
奉上四份代码

code(洛谷):

树状数组

#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline bool idigit(char x){return (x<'0'|x>'9')?0:1;}
inline int read()
{
	int num=0,f=1;
	char c=0;
	while(!idigit(c=getchar())){if(c=='-')f=-1;}
	while(idigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
	return num*f;
}
inline void write(int x)
{
	int F[20];
	int tmp=x>0?x:-x;
	if(x<0)putchar('-');
	int cnt=0;
	while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}
	while(cnt>0)putchar(F[--cnt]);
	if(x==0)putchar('0');
}
struct q{int id,val;}a[500010];
bool cmp1(q x,q y){return x.val<y.val;}
bool cmp2(q x,q y){return x.id<y.id;}
int n,tree[500010],ans=0,la=-1;
inline void add(int x,int k){for(;x<=n;x+=(x&-x))tree[x]+=k;}
inline int sum(int x){int q=0;for(;x;x^=(x&-x))q+=tree[x];return q;}
signed main()
{
	n=read();
	for(int i=1;i<=n;++i)a[i].val=read(),a[i].id=i;
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=n;++i)
	{
		if(a[i].val!=la)la=a[i].val,a[i].val=a[i-1].val+1;
		else a[i].val=a[i-1].val;
	}
	sort(a+1,a+n+1,cmp2);
	for(int i=1;i<=n;++i)add(a[i].val,1),ans+=i-sum(a[i].val);
	write(ans);
	return 0;
}

归并排序

#include<cstdio>
#define rr register int
#define int long long
using namespace std;
int n,a[500010],b[500010],ans;
inline void gb(int l,int r)
{
	if(l==r)return;
	rr mid=l+r>>1,p=l,j=mid+1,i=l;
	gb(l,mid),gb(j,r);
	while(l<=mid&&j<=r){if(a[j]<a[l])ans+=mid+1-l;b[p++]=(a[j]>=a[l])?a[l++]:a[j++];}
	while(l<=mid)b[p++]=a[l++];
	while(j<=r)b[p++]=a[j++];
	for(;i<=r;++i)a[i]=b[i];
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
	gb(1,n);
	printf("%lld",ans);
	return 0;
}

code(SSLOJ):

树状数组

#include<cstdio>
#define int long long
using namespace std;
inline bool idigit(char x){return (x<'0'|x>'9')?0:1;}
inline int read()
{
	int num=0,f=1;
	char c=0;
	while(!idigit(c=getchar())){if(c=='-')f=-1;}
	while(idigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
	return num*f;
}
inline void write(int x)
{
	int F[20];
	int tmp=x>0?x:-x;
	if(x<0)putchar('-');
	int cnt=0;
	while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}
	while(cnt>0)putchar(F[--cnt]);
	if(x==0)putchar('0');
	putchar('\n');
}
int n,tree[110],ans;
inline void add(int x){for(;x<=100;x+=(x&-x))++tree[x];}
inline int sum(int x){int q=0;for(;x;x^=(x&-x))q+=tree[x];return q;}
signed main()
{
	while(~scanf("%lld",&n)&&n)
	{
		ans=0;
		for(int i=1;i<=100;++i)tree[i]=0;
		for(int i=1;i<=n;++i)read(),ans=(ans+sum(tree[0]=read()))%1000000,add(tree[0]);
		write(((((n*(n-1))>>1)-ans)%1000000+1000000)%1000000);
	}
	return 0;
}

归并排序

#include<cstdio>
#define rr register int
#define int long long
using namespace std;
int n,a[250010],b[250010],ans;
inline void gb(int l,int r)
{
	if(l==r)return;
	rr mid=l+r>>1,p=l,j=mid+1,i=l;
	gb(l,mid),gb(j,r);
	while(l<=mid&&j<=r){if(a[j]<a[l])(ans+=mid+1-l)%=1000000;b[p++]=(a[j]>=a[l])?a[l++]:a[j++];}
	while(l<=mid)b[p++]=a[l++];
	while(j<=r)b[p++]=a[j++];
	for(;i<=r;++i)a[i]=b[i];
}
signed main()
{
	while(~scanf("%lld",&n)&&n)
	{
		ans=0;
		for(int i=1;i<=n;++i)scanf("%lld%lld",&a[0],&a[i]);
		gb(1,n);
		printf("%lld\n",ans);
	}
	return 0;
}
上一篇:TypeScript的索引类型与映射类型,以及常用工具泛型的实现


下一篇:尝试解析js面试题(一)【转发】