逆序对

依旧还是TT的评测
题目描述

有一个1 − n的排列,你会依次进行m次操作,第i次操作表示为(x i , y i ),交换以这两个
值为下标的元素,每次操作有一半的概率成功,你需要求出最后序列的逆序对的期望个数。

tips:期望值

输入

输入文件 inversion.in。
第一行两个数n, m。
第二行n个数表示初始的排列。
接下来m行,每行两个数表示x i , y i 。

输出

输出文件 inversion.out。
一个实数表示答案,四舍五入保留到小数点后 8 位,要求绝对误差不超过 10 -6 。
(评测时开启实数比较模式)

样例输入

4 3

1 3 2 4

1 2

2 3

1 4

样例输出

3.00000000

数据说明

30%: n ≤ 10, m ≤ 20
100%: n ≤ 1000, m ≤ 1000

思路

1.我们用一个f[i][j]数组储存i位置上的值和j位置上的值之间是否存在逆序对

2.然后输入我们要交换的2个位置x,y,用for循环来计算出他对每个的影响,因为每次操作有50%的成功几率,那么原来的f[x][i]和f[y][i]之间要*0.5

f[x][i]=f[y][i]=0.5*(f[x][i]+f[y][i]);

那么

f[i][x]=f[i][y]=1-f[x][i];

由于是x,y互换

所以f[x][y]=f[y][x]=0.5;

3.然后我们所需要做的就是把它们加起来,求出最后的期望值(期望个数)

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1050];
double ans=0;
double f[1010][1010];
int scan()//借鉴GQL的更新快读,please remember!!
{
    int as=0;
    bool y=1;
    char c=getchar();
    while(c!='-'&&(c>'9'||c<'0')) c=getchar();
    if(c=='-') y=0,c=getchar();
    while(c>='0'&&c<='9')
        as=(as<<3)+(as<<1)+(c^'0'),c=getchar();
    return y?as:-as;
}
int main()
{
    n=scan();
    m=scan();
    for(int i=1;i<=n;i++)
        a[i]=scan();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[i][j]=a[i]>a[j];//f[i][j]表示i和j之间是否存在逆序对
            //    cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
        }
    }
    while(m--)
    {
        int x=scan();//输入要交换的2个位置
        int y=scan();
        for(int i=1;i<=n;i++)//!!!!,x,y是2个位置
        {
            f[x][i]=f[y][i]=(double)0.5*(f[x][i]+f[y][i]);
            f[i][x]=f[i][y]=(double)1-f[x][i];
        }
        f[x][y]=f[y][x]=0.5;
    }
    ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            ans+=(double)f[i][j];
        }
    }
    printf("%.8lf",ans);
    return 0;
    
}
View Code
原文地址:https://www.cnblogs.com/KSTT/p/10327759.html