牛客IOI周赛26-提高组 A.逆序对(逆序对思维)

LINK


考虑一次操作对逆序数的影响

对于操作一交换 a l a_l al a r a_r ar

l e n = r − l − 1 len=r-l-1 len=rl1

先考虑 a l a_l al a r a_r ar形成的逆序对数为 k k k,那么交换后数量为 1 − k 1-k 1k

考虑 a l a_l al a [ l + 1... r − 1 ] a[l+1...r-1] a[l+1...r1]形成 z z z个逆序对,那么交换之后就形成 l e n − z len-z lenz个逆序对

考虑 a r a_r ar a [ l + 1... r − 1 ] a[l+1...r-1] a[l+1...r1]形成 r r r个逆序对,那么交换之后就形成 l e n − r len-r lenr个逆序对

也就是开始逆序对数为 z + r + k z+r+k z+r+k,交换后为 z + r + 2 l e n + ( 1 − k ) z+r+2len+(1-k) z+r+2len+(1k)

显然交换先后的奇偶性一定不同。

再考虑操作二翻转整个区间 [ l , r ] [l,r] [l,r]

l e n = r − l + 1 len=r-l+1 len=rl+1,且翻转前区间逆序对为 x x x

那么反转后区间逆序对为 l e n ∗ ( l e n − 1 ) / 2 − x len*(len-1)/2-x len(len1)/2x

考虑当 l e n ∗ ( l e n − 1 ) / 2 len*(len-1)/2 len(len1)/2为偶数时翻转前后同奇偶,是奇数不同奇偶…

操作三,操作四同理,很容易就可以得到本次操作是否会改变奇偶性

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int n,m,a[maxn],sum[maxn];
int lowbit(int x){ return x&(-x); }
void add(int x,int val){ for(;x<=n;x+=lowbit(x)) sum[x] += val; }
int ask(int x){ int ans = 0; for( ; x ; x-=lowbit(x)) ans += sum[x]; return ans; }
int main()
{
	scanf("%d%d",&n,&m );
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	int chu = 0;
	for(int i=n;i>=1;i--)
	{
		chu ^= ( 1&ask( a[i] ) );;
		add( a[i],1 );
	}
	int type,l,r,k,len; 
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&type,&l,&r);
		len = r-l+1;
		if( type==1 ) chu ^= 1;//啥也不干 
		else if( type==2 )
		{
			if( 1ll*len*(len-1)/2&1 )	chu ^= 1;
		}
		else
		{
			scanf("%d",&k );
			k %= (r-l+1);
			int yu = r-l+1-k;
			if( (yu&1) && (k&1) )	chu ^= 1;
		}
		if( chu&1 )	puts("1");
		else	puts("0");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值