洛谷 P1428 小鱼比可爱 知识点:双指针 ,树状数组

95 阅读2分钟

P1428 小鱼比可爱 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题目的意思实际上有点像求逆序对的个数(从右往左看),

模拟一下:

image.png

这个时候j--,我们发现a[i]大于a[j],我们对应位置上的计数++。

image.png

j继续--:

image.png

image.png

#include<bits/stdc++.h>
using namespace std;
int a[1110],b[110];
int main()
{
	int n;cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	
	for(int i=0;i<n;i++)
	{
		for(int j=i;j>=0;j--)
		{
			if(a[i]>a[j])b[i]++;
		}
	 } 
	 
	 for(int i=0;i<n;i++)cout<<b[i]<<" ";
	 cout<<endl;
	return 0;
}

image.png

既然是求逆向的逆序对,那么就可以用树状数组来做:

树状数组就是用数组的和做出一个树

大概的思路就是A数组表示每种数有多少个

比如数据是 4 4 3 2 1 那么a[4] = 2,a[3] = 1,a[2]=1,a[1] =1

然后每次只需要找一下对应的C数组就好了

具体模拟一下样例吧

4 3 0 5 1 2

第一步:输入4 此时a数组为 0 0 0 0 1 0 0 0 ... (有一个4,所以a[4] = 1)然后计算一下a[0]+a[1]+a[2]+a[3]=0,然后第一个结果就是0

第二步:输入3 此时a数组为 0 0 0 1 1 0 0 0 ... 计算一下a[0]+a[1]+a[2]=0,输出0

第三步:输入0 此时a数组为 1 0 0 1 1 0 0 0 ... 输出0

第四步:输入5 此时a数组为 1 0 0 1 1 0 0 0 ... 计算a[0]+...+a[4] = 3,输出3

.... 所以结果就出来了

但是树状数组再操作的时候不对原来的a数组操作,而是对求和的c数组进行操作,而且C数组的第一位不能为0,所以把角标往后窜一位。。于是就变成了

a[3]代表有几个2 ,a[4]代表有几个3。。。

那上边的第二步来举例,就变成 输入3,之后a数组就是 0 0 0 0 1 1 0 0....计算计算一下a[1]+a[2]+a[3]=0,输出0

所以每次输入x,结果就是sum(x), 然后维护一遍树就可以了。。(输入3,所以a[4]要加1, 于是就变成了add(x+1))

#include<bits/stdc++.h>
using namespace std;
int tree[1110],b[110];
int n,x;

int lowbit(int x)
{
	return x&(-x);
}


void add(int x)
{
	while(x<100)
	{
	   tree[x]++;
	   x+=lowbit(x);
	}
}

int sum(int x)
{
	int ans=0;
	while(x>0)
	{
		ans+=tree[x];
		x-=lowbit(x);
	}
return ans;
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
    {
    	cin>>x;
		//每次输入一个值,计算他之前的和
		if(i==0)cout<<sum(x);  

		else cout<<" "<<sum(x);
		
		add(x+1); 
	 } 
cout<<endl;
	return 0;
}

image.png