[题解] [JSOI2015] 非诚勿扰

题面

题解

设第 \(k\) 个女性的如意郎君列表长度为 \(len\) , 那么我们选择这其中第 \(i\) 位的概率是

\[\displaystyle\begin{aligned}&p*(1-p)^{i - 1} *\sum_{j = 0}^{\infty}(1-p)^{j*len}\\=&\frac{p*(1-p))^{i-1}}{1-(1-p)^len}\end{aligned} \]

把后面拿个等比数列求下和即可, 因为是无穷项, 所以 \((1-p)^\infty \to 0\), 直接扔了

发现这个东西可以树状数组维护, 没了

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
const int N = 5e5 + 5;
#define double long double
using namespace std;

int n, m;
double t[N], p, ans; 
vector<int> g[N]; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

void add(int x, double y)
{
    for(int i = x; i <= n; i += (i & -i)) t[i] += y; 
}

double query(int x)
{
    double res = 0;
    for(int i = x; i > 0; i -= (i & -i)) res += t[i];
    return res; 
}

int main()
{
    n = read <int> (), m = read <int> (), scanf("%Lf", &p);
    for(int u, v, i = 1; i <= m; i++)
    {
	u = read <int> (), v = read <int> ();
	g[u].push_back(v); 
    }
    double tmp; 
    for(int sz, i = 1; i <= n; i++)
    {
	sz = g[i].size(), sort(g[i].begin(), g[i].end()); 
	tmp = p / (1 - pow(1.0 - p, sz)); 
	for(int j = 0; j < sz; j++, tmp *= (1 - p))
	    ans += (query(n) - query(g[i][j])) * tmp, add(g[i][j], tmp);
    }
    printf("%.2Lf\n", ans); 
    return 0; 
}
posted @ 2020-02-24 20:38  ztlztl  阅读(170)  评论(0编辑  收藏  举报