[理综考试]

一场理综考试中有n个考生,编号为1~n,第i个考生的得分是[li,ri]中随机的一个实数

求每个考生得到每个排名的概率

Input

8
0 2
1 3
2 4
3 5
4 6
5 7
6 8
7 9

 

Output

0 0 0 0 0 0 0.125 0.875
0 0 0 0 0 0.125 0.75 0.125
0 0 0 0 0.125 0.75 0.125 0
0 0 0 0.125 0.75 0.125 0 0
0 0 0.125 0.75 0.125 0 0 0
0 0.125 0.75 0.125 0 0 0 0
0.125 0.75 0.125 0 0 0 0 0
0.875 0.125 0 0 0 0 0 0

 

绝对误差不超过10^-6算作正确

 

 

Sol:

考虑将区间离散,得到这个人分散在一些小区间以及在每个小区间的概率

枚举每一个人以及他的所属区间,得到一个概率P

因为可能会有重叠,所以设f[i][j]代表有i个人比这个人名次靠后,j个人和他在一个区间内的概率

转移见代码,注意概率计算

那么枚举i和j,这个人在[i+1,i+j+1]的排名的概率为f[i][j] * p * 1/(j+1)

累加进答案。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100
#define eps 1e-12
using namespace std;

int n, L[maxn], R[maxn], h[maxn*2], cnt, ll, rr;
double g[maxn], f[maxn][maxn];

double getwin(int i){
	if(R[i] <= rr)return 0;
	if(L[i] >= rr)return 1;
	return (double)(R[i]-rr)/(R[i]-L[i]);
}

double getlose(int i){
	if(R[i] <= ll)return 1;
	if(L[i] >= ll)return 0;
	return (double)(ll-L[i])/(R[i]-L[i]);
}

void solve(int nw, int k){
	ll = h[k], rr = h[k+1];
	double p = (double)(rr-ll) / (R[nw]-L[nw]);
	memset(f, 0, sizeof f); f[0][0] = 1;
	for(int i = 1; i <= n; i ++){
		if(i == nw)continue;
		double win = getwin(i), lose = getlose(i), equal = 1.0-win-lose;
		for(int j = i-1; j >= 0; j --){
			for(int k = i-1-j; k >= 0; k --)if(f[j][k] > eps){
				f[j+1][k] += lose * f[j][k];
				f[j][k+1] += equal * f[j][k];
				f[j][k] = win * f[j][k];
			}
		}
	}
	
	for(int i = 0; i < n; i ++)
		for(int j = 0; j < n-i; j ++)
			for(int k = 0; k <= j; k ++)
				g[i+k] += f[i][j]*p/(j+1);
}

int main(){
	freopen("gg.in", "r", stdin);
	freopen("gg.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++){
		scanf("%d%d", &L[i], &R[i]);
		h[++ cnt] = L[i], h[++ cnt] = R[i];
	}
	sort(h+1, h+1+cnt);
	cnt = unique(h+1, h+1+cnt)-h-1;
	//for(int i = 1; i <= cnt; i ++)cout << h[i] << ' ';cout << endl;
	for(int i = 1; i <= n; i ++){
		memset(g, 0, sizeof g);
		int l = lower_bound(h+1, h+1+cnt, L[i]) - h;
		int r = lower_bound(h+1, h+1+cnt, R[i]) - h;
		for(int j = l; j < r; j ++)solve(i, j);
		for(int j = n-1; ~ j; j --)
			printf("%.10lf ", g[j]); puts("");
	}
	return 0;
}

  

posted @ 2016-06-19 17:05  _Horizon  阅读(191)  评论(0)    收藏  举报