题意:
给你一个数列&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
]
<
a
[
y
]
a[x]<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);
}