E. Startup Funding
题目连接:
http://codeforces.com/contest/633/problem/E
Description
An e-commerce startup pitches to the investors to get funding. They have been functional for n weeks now and also have a website!
For each week they know the number of unique visitors during this week vi and the revenue ci. To evaluate the potential of the startup at some range of weeks from l to r inclusive investors use the minimum among the maximum number of visitors multiplied by 100 and the minimum revenue during this period, that is:
The truth is that investors have no idea how to efficiently evaluate the startup, so they are going to pick some k random distinct weeks li and give them to managers of the startup. For each li they should pick some ri ≥ li and report maximum number of visitors and minimum revenue during this period.
Then, investors will calculate the potential of the startup for each of these ranges and take minimum value of p(li, ri) as the total evaluation grade of the startup. Assuming that managers of the startup always report the optimal values of ri for some particular li, i.e., the value such that the resulting grade of the startup is maximized, what is the expected resulting grade of the startup?
Input
The first line of the input contains two integers n and k (1 ≤ k ≤ n ≤ 1 000 000).
The second line contains n integers vi (1 ≤ vi ≤ 107) — the number of unique visitors during each week.
The third line contains n integers ci (1 ≤ ci ≤ 107) —the revenue for each week.
Output
Print a single real value — the expected grade of the startup. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.
Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if .
Sample Input
3 2
3 2 1
300 200 300
Sample Output
133.3333333
Hint
题意
有n个人,每个人有两个权值,v[i]和c[i]
然后有一个函数p(l,r) = min(100*max(v[l..r]),min(c[l..r]))
对于每一个i,你需要找到一个最大的p(i,ri)
然后现在从n个p(i,ri)中选取k个,然后再从这k个中选取其中最小的
问你选出来的数的期望是多少
题解:
首先处理第一个问题,对于每一个i如何确定一个最大的p(i,ri)
我们看到v[l..r]是一个单调递增的函数,c[l..r]是一个单调递减的函数
这两个函数取min,肯定是个单峰函数,我们直接二分找到峰值,那么我就就得到了p(i,ri)了
然后我们再处理第二个问题,期望怎么算
我们首先把所有的p(i,ri)从小到大排序,那么最后选出第i个数的概率是C(n-i,k-1)/c(n,k)
从n-i个数里面选择k-1个出来,这是贡献这个的概率
总共有c(n,k)种选择
这个组合数是可以递推的,然后我们搞一搞就出来了咯。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
struct RMQMAX{
const static int RMQ_size = maxn;
int n;
int ArrayMax[RMQ_size][21];
void build_rmq(){
for(int j = 1 ; (1<<j) <= n ; ++ j)
for(int i = 0 ; i + (1<<j) - 1 < n ; ++ i){
ArrayMax[i][j]=max(ArrayMax[i][j-1],ArrayMax[i+(1<<(j-1))][j-1]);
}
}
int QueryMax(int L,int R){
int k = 0;
while( (1<<(k+1)) <= R-L+1) k ++ ;
return max(ArrayMax[L][k],ArrayMax[R-(1<<k)+1][k]);
}
void init(int * a,int n){
this->n = n ;
for(int i = 0 ; i < n ; ++ i) ArrayMax[i][0] = a[i];
build_rmq();
}
}S1;
struct RMQMIN{
const static int RMQ_size = maxn;
int n;
int ArrayMin[RMQ_size][21];
void build_rmq(){
for(int j = 1 ; (1<<j) <= n ; ++ j)
for(int i = 0 ; i + (1<<j) - 1 < n ; ++ i){
ArrayMin[i][j]=min(ArrayMin[i][j-1],ArrayMin[i+(1<<(j-1))][j-1]);
}
}
int QueryMin(int L,int R){
int k = 0;
while( (1<<(k+1)) <= R-L+1) k ++ ;
return min(ArrayMin[L][k],ArrayMin[R-(1<<k)+1][k]);
}
void init(int * a,int n){
this->n = n ;
for(int i = 0 ; i < n ; ++ i) ArrayMin[i][0] = a[i];
build_rmq();
}
}S2;
int n,k,v[maxn],c[maxn],val[maxn],a[maxn];
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&v[i]);
for(int i=0;i<n;i++)
scanf("%d",&c[i]);
S1.init(v,n+1);
S2.init(c,n+1);
for(int i=0;i<n;i++)
{
int l=i,r=n-1,nxt=i;
while(l<=r)
{
int mid=(l+r)/2;
if(S1.QueryMax(i,mid)*100<S2.QueryMin(i,mid))l=mid+1,nxt=mid;
else r=mid-1;
}
int L = min(S1.QueryMax(i,nxt)*100,S2.QueryMin(i,nxt));
int R = min(S1.QueryMax(i,nxt+1)*100,S2.QueryMin(i,nxt+1));
val[i]=max(L,R);
}
sort(val,val+n);
double p = 1.0*k/(1.0*n);
double ans = p*val[0];
for(int i=1;n>=i+k;i++)
{
p = p*(1.0*n-i-k+1)/(1.0*n-i);
ans+=p*val[i];
}
printf("%.12f
",ans);
return 0;
}