题意:
给出一个长度为 n n n的全排列数组和 m m m 对二元组 ( l , p ) (l,p) (l,p),表示有 p p p 的概率对 区间 ( 1 , l ) (1,l) (1,l) 进行排序,问最终数组完全升序的概率。
题解:
不难发现,数组总能找到一个位置,使得后缀满足 a i = i a_i=i ai=i ,前缀乱序,要想使得数组升序,排序的右区间必须 ≥ \geq ≥ 该位置。
所以我们不需要去考虑 l i l_i li 小于此位置的数,那么接下来怎么计算剩下的 l i l_i li 至少有一个被选的概率呢?
既然正向算不好算,那就反向,只要计算出剩下的 l i l_i li 都没被选的概率,那么根据容斥,即可得出至少一个的概率。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod = 1e9 + 7;
const int MAXN = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int a[MAXN];
int l[MAXN];
double p[MAXN];
int main()
{
//=========================================
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
//=========================================
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int pos=-1;
for(int i=n;i>=1;i--)
{
if(a[i]!=i)
{
pos=i;
break;
}
}
double ans=1;
if(pos==-1) pos=n+1;
for(int i=1;i<=m;i++)
{
cin>>l[i]>>p[i];
if(l[i]>=pos)
{
ans=ans*(1-p[i]);
}
}
//cout<<pos<<endl;
if(pos==n+1) printf("%.8lf\n",ans);
else printf("%.8lf\n",1-ans);
}
}