逆序对 inversion

    评测传送门

【问题描述】
  有一个1 − n的排列,你会依次进行m次操作,第i次操作表示为(x i , y i ),交换以这两个
  值为下标的元素,每次操作有一半的概率成功,你需要求出最后序列的逆序对的期望个数。
【输入】
  输入文件 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

gql的方法:

  把逆序对的期望数分开来算

  f[i][j] 表示编号为 i 的数大于编号为 j 的数的概率

  维护这个数组

  统计答案的时候就直接吧所有 i<j 时的 f[i][j] 相加即可

  怎么维护这个数组呢

  首先输入完n个数后 可以初始化得出最初的 f[ ][ ]

  然后边输入 xi yi 边更新 f[ ][ ]  具体见代码啦

 1 #include<iostream>
 2 #include<cstdio>
 3 #define go(i,a,b) for(register int i=a;i<=b;i++)
 4 #define db double
 5 using namespace std;
 6 int read()
 7 {
 8     int x=0,y=1;char c=getchar();
 9     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
10     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
11     return x*y;
12 }
13 int n,m,x,y,a[1010];
14 db f[1010][1010],ans;
15 int main()
16 {
17     //freopen("1.in","r",stdin);
18     //freopen("1.out","w",stdout);
19     n=read();m=read();
20     go(i,1,n) a[i]=read();
21     go(i,1,n) go(j,1,n) if(a[i]>a[j]) f[i][j]=1;
22     go(i,1,m)
23     {
24         x=read();y=read();
25         go(j,1,n)
26         {
27             f[x][j]=f[y][j]=(f[x][j]+f[y][j])*0.5;
28             f[j][x]=f[j][y]=1-f[x][j];
29         }
30         f[x][y]=f[y][x]=0.5;
31     }
32     go(i,1,n) go(j,i+1,n) ans+=f[i][j];
33     printf("%.8lf",ans);
34     return 0;
35 }
View Code

    

posted @ 2019-01-27 17:21  DTTTTTTT  阅读(233)  评论(0编辑  收藏  举报