[题解] [JSOI2015] 非诚勿扰

淺唱寂寞╮ 提交于 2020-02-24 22:01:09

题面

题解

设第 \(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; 
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!