水一波题解之NOI.oj:7622:求排列的逆序数 [ 首文 附创作声明]【区间dp,二分法,下标地址抽象】

26 篇文章 1 订阅
26 篇文章 0 订阅

7622:求排列的逆序数 题解

原题见此处

首先看见题目后先想到的当然是O(nlogn)的暴力算法,于是第一码诞生:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define SIZE_ 100001
unsigned long long n,i,j,value[SIZE_],anss;
int main()
{
 for(cin>>n;i<n;i++)
    {
	 cin>>value[i];
	 for(j=0;j<i;j++)
	    if(value[j]>value[i])
	      anss++;
	}
 cout<<anss;
 return 0;
}


很简洁的代码,绝对无错但是时效过低,T了四个点

然后开始思考怎么才能避免重复判断比较大小记录结果?

简单的不等式性质:若 a>b,b>c 则 a>c

有点分治的味道了

所以说当确定一个数它左边比它大的数一定比它右边比它小的数大(听上去很拗口建议先考虑断句再读>.<)

分治算法是要两侧的计算互不影响,那我们就要考虑以下情况: 有数列a,b,c,其中$a>b,b<c,a>c$的情况呢??

只要在比较之后交换a,b(或b,c)就可以不重不漏地记录下对答案的贡献

不难看出,这个过程与二分排序相似,不过此处求的是操作数而不是结果的有序数列(我们已经知道的1~n)


为了解释相应的算法,我们来举个栗子(真香) : 


求该排列中的逆序数

流程表如下:

那么根据以上描述就可以得到下面这串代码:

#include<iostream>
using namespace std;
#define SIZE_ 100001
unsigned long long n,i,j,
value[SIZE_],anss;
void divcount(unsigned int l,unsigned int r)
{
 if(l==r)
   return;
 register unsigned int mid=(l+r)/2,i=l,j=mid+1;
 divcount(l,mid);
 divcount(mid+1,r);
 unsigned int k=0,temp[r-l];
 while(i<=mid&&j<=r)
   if(value[i]<=value[j])
     temp[++k]=value[i++];
   else
     {
      temp[++k]=value[j++];
      anss+=mid-i+1;
     }
 while(i<=mid)temp[++k]=value[i++];
 while(j<= r )temp[++k]=value[j++];
 for(i=1;i<=k;i++)
    value[i+l-1]=temp[i];
 return;
}
int main()
{
 for(cin>>n;i<n;i++)
     cin>>value[i];
 divcount(0,n-1);
 cout<<anss;
 return 0;
}

    

啊哈AC!

 

由于这是本人的第一篇博文,在最后附上创作声明:


 

创作声明


  1. 首先,本博主对计算机科学、数学等方面学术略有研究,并希望更好的利用业余时间,写些又实在意义的文字,所以就有了第二条(滑稽)
  2. 如果看到此声明的你有什么学术上的疑惑,私信博主,如果问题在博主的水平范围内即会推出相应的解题报告来解答,也顺便谈谈博主对此问题的看法。
  3. 如果文章存在错误还请见谅,并且请立即私信博主,博主将会在第一时间给予改正。
  4. 有什么好的建议(像“不喜欢这么不正经的文风”之类还是藏在心里别告诉我比较好,嘻嘻)或是意见都欢迎私信博主哦(>.<)!
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值