M. Youth Finale

M. Youth Finale

题目连接

题目大意就是首先求出给出序列的逆序对,然后根据两个不同的操作,对序列进行改变后,再求它的逆序列。

第一个操作思维

首先可以肯定的是这序列是由1~n组成的,由此,当我们执行左移循环操作时,假设当前序列头是a0该序列会减少(a0-1)个,(因为能构成逆序对的必然是在它之后且比他小的数),会增加(n-a0)个,当它到尾巴后,显然能构成逆序列的就只有比它大的数了。
s u m − = a 0 − 1 ; s u m + = n − a 0 sum-=a_0 -1;sum+=n-a0 sum=a01;sum+=na0

第二个操作思维

由于倒过来了,那么逆序对就会变成正序对,而正序对就会变成逆序对,我们只需要求出正序对和逆序对之和即可。
s u m = n ∗ ( n − 1 ) 2 sum = \frac{n*(n-1)}{2} sum=2n(n1)
再用sum - 当前的逆序对之和。即可得到翻转后的逆序对数目。

整体设计思维

首先要求出初始序列的逆序对数目,我们可以通过树状数组求逆序对。不了解的可以去学习一下树状数组是什么。

当求出初始逆序对数目之后,只需要考虑前两个思维,加上当前序列的头是谁(也就是维护头),即可求解。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int lim = 6e5+10;
int count_[lim];
int a[lim];

int getLowOneBit(int t)
{
	return t&-t;
}

void add_(int t) 
{
	while(t<=n)
	{
		count_[t]++;
		t+=getLowOneBit(t);
	}
}

int get_(int t)
{
	int ans=0; 
	while(t>=1)
	{
		ans+=count_[t] ;
		t-=getLowOneBit(t);
	}
	return ans;
}

signed main(){
	cin>>n>>m; 
	//使用树状数组求逆序对
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		add_(a[i]);
		//求出在它之前比他小的树的数量a,就可以用当前所有元素的数量- a即可得到在它之前,比他大的数量 
		sum+=i -get_(a[i]);
	}
	cout<<sum<<"\n";
	string s;
	cin>>s;
	int sum2 = n*(n-1)/2;//逆序对和正序对的总和 
	int head = 1;
	bool dir = 1;
	for(int i=0;i<s.length();i++) 
	{
		 if(s[i]=='S')
		 {
			sum-=a[head]-1;
			sum+=n - a[head];
			if(dir) head++;
			else head--;
		 }
		 else
		 {
		 	//逆序对数量和正序对数量,两者交换 
		 	sum = sum2 - sum;
		 	if(dir)head--;
		 	else head++;
		 	dir = !dir;
		 }
		 if(head==0) head=n;
		 if(head==n+1) head=1;
		 cout<<sum%10;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值