CF 362C 冒泡排序 交换哪两个数逆序数减少最多

交换两个数,求使得排列的逆序数最多减少多少,以及有多少个这样的数对

数据范围有5000,我的算法是n^2logn

因为有n^2个询问,所以最好O(1)的回答,所以需要先预处理一下。

怎样快速回答交换两个数之后逆序数的改变呢?

这就要快速的算出i和j之间有多少个比num[i]小的数,有多少个比num[j]小的数,比它们大的数一减就OK。

设 si为i到j中比i小的数 bi为比i大的数 sj为比j小的数,bj为比j大的数。

所以逆序数减少量为旧逆序数-新逆序数=si-bi+bj-sj-1 最后那个1是指i和j交换后减少的逆序数。

#include<stdio.h>
#include<string.h>


int res[5200][5200];//到i为止小于num[j]的数字
int bit[5200],n;
int num[5200];

int sum(int i)
{
	int s=0;
	while(i>0)
	{
		s+=bit[i];
		i -= i & -i;
	}
	return s;
}

void add(int i,int x)
{
	while(i<=n)
	{
		bit[i]+=x;
		i += i & -i;
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&num[i]);
		num[i]++;
	}
	memset(bit,0,sizeof(bit));
	memset(res,0,sizeof(res));
	int tot=0;
	for(int i=1;i<=n;i++)
	{
		add(num[i],1);
		for(int j=1;j<=n;j++)
		{
			if(num[j]==0) continue;
			res[i][j]=sum(num[j]-1);
		}
		if(num[i]==0) continue;
		tot+=(i-sum(num[i]));
	}
	
	int max_=-1;
	int ans=0;
	for(int i=1;i<n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			if(num[i]>num[j])
			{
				int tn=j-i-1;
				int si=res[j][i]-res[i][i];
				int bi=tn-si;
				int sj=res[j][j]-res[i][j];
				int bj=tn-sj;
				int t=si-bi+bj-sj-1;
				if(t>max_)
				{
					max_=t;
					ans=1;
				}else if(t==max_)
				{
					ans++;
				}
			}
		}
	}	
	printf("%d %d\n",tot-max_,ans);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值