【问题描述】
有一个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[ ][ ] 具体见代码啦
View Code1 #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 }