AtCoder Grand Contest 030D - Inversion Sum

37 篇文章 0 订阅
16 篇文章 0 订阅

题意:

给你一个数列&a_i&,有若干操作,可以交换 a [ x i ] , a [ y i ] a[x_i],a[y_i] a[xi],a[yi],你也可以不进行这个操作。
对于所有 2 Q 2^Q 2Q种操作方式,问逆序对总和是多少。

题解:

容易想到 f i , x , y f_{i,x,y} fi,x,y表示前i个操作,使得 a [ x ] &lt; a [ y ] a[x]&lt;a[y] a[x]<a[y]的方案数。
然后没法转移。
膜题解,发现只要转为求期望,最后再乘回去即可。
因为这样对于操作 x i , y i x_i,y_i xi,yi,就只会影响跟 x i x_i xi y i y_i yi有关的这 2 n 2n 2n对数。
剩下的就是期望dp常规题了。
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const LL mod=1e9+7;
LL n,q,a[3010],Q;
LL f[3010][3010];
LL fp(LL a,LL b)
{
	LL ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans;
}
const LL inv=fp(2,mod-2);
int main()
{
	scanf("%lld %lld",&n,&q);Q=q;
	for(LL i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(LL i=1;i<=n;i++)
		for(LL j=1;j<=n;j++) f[i][j]=(a[i]<a[j]);
	while(q--)
	{
		LL x,y;scanf("%lld %lld",&x,&y);
		f[x][y]=f[y][x]=(f[x][y]+f[y][x])*inv%mod;
		for(LL i=1;i<=n;i++)
			if(i!=x&&i!=y)
			{
				f[i][x]=f[i][y]=(f[i][x]+f[i][y])*inv%mod;
				f[x][i]=f[y][i]=(f[x][i]+f[y][i])*inv%mod;
			}
	}
	LL ans=0;
	for(LL i=1;i<=n;i++)
		for(LL j=1;j<i;j++) (ans+=f[i][j])%=mod;
	(ans*=fp(2,Q))%=mod;
	printf("%lld",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值