题目描述
要考研了,小码哥非常焦急,他要开始背英语单词,每个单词的长度是lil_ili ,小码哥有pipipi的概率认识这个单词,小码哥要从一个有nnn个单词的总清单里按顺序的背单词,小码哥有一个认识清单,里面放的都是他认识的单词,如果小码哥背到第iii个单词不认识这个单词,小码哥会把该单词背一遍并且把自己认识的单词从头背一遍,如果小码哥认识这个单词,他会把该单词背一遍,并且把这个单词放进自己的认识清单里。问如何排序小码哥背单词的长度的期望最大,期望是多少。
输入格式
第一行包含单个整数n(1≤n≤50000)n(1\le n\le 50000)n(1≤n≤50000)。下面nnn行中的第iii行包含两个整数,用一个空格隔开lil_ili和pip_ipi(1≤li≤1000,0≤pi≤1001\le l_i\le 1000,0\le pi\le 1001≤li≤1000,0≤pi≤100)——第iii个单词的长度和小码哥认识这个单词的概率(以百分比为单位)。
输出格式
单行打印单个实数表示小码哥背单词的长度的最大期望。绝对误差或相对误差不超过10−910^{-9}10−9。
输入样例1
3
100 6
100 8
100 10
输出样例1
326.12
输入样例2
5
100 6
100 8
100 10
2 99
1000 1
输出样例2
1364.045
分析
我们要为所有的单词排一个顺序,使得最终背诵的单词长度期望最大。
设wiw_iwi为单词iii的权值 li∗pil_i*p_ili∗pi。
假设a、b两个单词,如果小码哥先背b后背a,那么他背到a的时候期望要加上
la∗pa+(1−pa)∗(w其他+wb+wa)(1)l_a*p_a+(1-p_a)*(w_{其他}+w_b+w_a)\qquad (1)la∗pa+(1−pa)∗(w其他+wb+wa)(1)
如果先背a后背b那么背到b时他的期望要加上:
lb∗pb+(1−pb)∗(w其他+wb+wa)(2)l_b*p_b+(1-p_b)*(w_{其他}+w_b+w_a)\qquad (2)lb∗pb+(1−pb)∗(w其他+wb+wa)(2)
我们给(1)式子乘上(1−pb)(1-p_b)(1−pb),(2)式乘上(1−pa)(1-p_a)(1−pa):
la∗pa∗(1−pb)+(1−pa)∗(1−pb)∗(w其他+wb+wa)(1)l_a*p_a*(1-p_b)+(1-p_a)*(1-p_b)*(w_{其他}+w_b+w_a)\qquad (1)la∗pa∗(1−pb)+(1−pa)∗(1−pb)∗(w其他+wb+wa)(1)
lb∗pb∗(1−pa)+(1−pb)∗(1−pa)∗(w其他+wb+wa)(2)l_b*p_b*(1-p_a)+(1-p_b)*(1-p_a)*(w_{其他}+w_b+w_a)\qquad (2)lb∗pb∗(1−pa)+(1−pb)∗(1−pa)∗(w其他+wb+wa)(2)
之后我们会发现一个公共项可以约掉:
(1−pa)∗(1−pb)∗(w其他+wa+wb)(1-p_a)*(1-p_b)*(w_{其他}+w_a+w_b)(1−pa)∗(1−pb)∗(w其他+wa+wb)
如果(1)−(2)>0(1)-(2)>0(1)−(2)>0:
la∗pa∗(1−pb)−lb∗pb∗(1−pa)>0(3)l_a*p_a*(1-p_b)-l_b*p_b*(1-p_a)>0\qquad (3)la∗pa∗(1−pb)−lb∗pb∗(1−pa)>0(3)
所以我们要取到最优解,就要满足(3)(3)(3)式的排序方法。
排序后将所有的概率和权值相乘后累加即可。
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-9;
//定义一个结构体
struct node{
int len,theta;
bool operator<(const node &p) const{
if(len*theta*(1-1.0*p.theta/100)-p.len*p.theta*(1-1.0*theta/100))
{
//满足关系(3)进行排序
if(len*theta*(1-1.0*p.theta/100)>p.len*p.theta*(1-1.0*theta/100)){
return 1;
}
}
return 0;
};
};
int n,,l,r;
long double ans,Summul;
int main()
{
vector<node> v,maxn;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>l>>r;
v.push_back({l,r});
}
sort(v.begin(),v.end());
for(int i=0;i<n;i++)
{
//加上这个单词的期望
ans+=(long double)v[i].len*v[i].theta*1.0/100+(long double)(Summul+v[i].len)*(1-v[i].theta*1.0/100);
//更新 w其他
Summul+=(long double)v[i].len*v[i].theta*1.0/100;
}
//将答案转换为字符串形式
string s=to_string(ans);
//将小数点后的多余的'0'给去掉
while(s.back()=='0') s.pop_back();
cout<<s;
return 0;
}
本文介绍了一种通过优化单词背诵顺序来最大化背诵效率的方法。通过对单词按特定条件排序,实现背诵长度期望值的最大化。
1578

被折叠的 条评论
为什么被折叠?



