[题解] [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;
}