Comet OJ - Contest #2 B 她的想法、他的戰鬥(概率 + 數學)
題目描述
Takuru 是一名情報強者,所以他想利用他強大的情報搜集能力來當中間商賺差價。
Takuru 的計劃是讓 Hinae 幫他去市場上買一個商品,然後再以另一個價格賣掉它。Takuru 會給 Hinae 一定的錢 p?p?。(p?p? 是一個非負的實數)
這個商品的市場價是一個在 [l, r]?[l,r]? 內均勻隨機的實數。
如果 p \geqslantp? 市場價,那麽 Hinae 會買下這個商品,然後私吞剩下的錢。也就是說,Takuru 以 pp 的代價買來了這個商品。
如果 p <p< 市場價,那麽 Hinae 既不會買下商品,又不會私吞任何錢。也就是說,Takuru 的利潤為 0?0?。
當 Hinae 買下了商品後,Takuru 會生成一個在 [L, R][L,R] 內均勻隨機的實數 qq,並把商品以 qq 的價格賣掉。那麽 Takuru 的利潤就是 q - p?q−p?。
Takuru 想要獲得最多的利潤,所以你要幫 Takuru 確定給 Hiane 的錢 pp,使得 Takuru 的期望利潤最大。請求出最大的期望利潤。
輸入描述
第一行兩個正整數 ll 和 rr (1\leqslant l < r \leqslant 20001?l<r?2000)。
第二行兩個正整數 LL 和 RR (1\leqslant L < R \leqslant 20001?L<R?2000)。
輸出描述
一個實數,表示最大的期望利潤。(四舍五入後保留 44 位小數,輸出超過 44 位或少於 44位都會獲得 Wrong Answer。)
如果答案為 00,請不要輸出多余的負號。
若答案為 vv,保證 v+10^{-6}v+10−6 以及 max(v-10^{-6},0)max(v−10−6,0) 四舍五入後保留 44 位小數的結果不會改變。
樣例輸入 1
400 1200 600 1800
樣例輸出 1
200.0000
樣例輸入 2
1999 2000 1 2
樣例輸出 2
0.0000
思路:因為主人公的售價是 L~R 所以 主人公售價的期望是 (L+R)/2
我們給買手的錢是p,那麽我們主人公的利潤就是 ((L+R)/2-p)
我們知道 期望=值*概率
利潤期望=利潤值*概率
我們來看下概率,
P必須取到 l和r之間,因為如果p大於r,那麽不是最優的選擇,因為可以選擇r可以產生更好的利益。
而p小於l的話,買手會無法購物商品,所以也不可以。
那麽p就在 l和r之間了,
買手能買商品的時候當且僅當 商品的市場價 恰好小於等於p,也就是市場價y小於p時,可以購買,
那麽y的範圍時 l~p,總範圍是l~r,所以概率是 (p-l)/(r-l)
期望就是
((L+R)/2-p)*(p-l)/(r-l)
公式就是一個關於p的二次函數,並且a是小於等於0的,有極大值,我們判定對稱軸是否在l到r之間,
如果在,那麽函數的極值就是答案,如果不在,那麽取區間的左右極限的較大值是答案。
註意處理以下0*負數=-0的情況,
細節見code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), ‘\0‘, sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;} inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ double l,r; double L,R; int main() { //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); gbtb; cin>>l>>r; cin>>L>>R; double t=(L+R)/2.00; double k=(r-l); double a=-1.00/k; double b=(t+l)/k; double c=-l*t/k; double x=-b/(2.00*a); double ans; if(x>=l&&x<=r) { ans=(4*a*c-b*b)/(4*a); // db(a*x*x+b*x+c); }else { ans=a*l*l+b*l+c; ans=max(ans,a*r*r+b*r+c); } ans+=eps; ans=max(0.0,ans-eps); cout<<fixed<<setprecision(4)<<ans<<endl; return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ‘ ‘ || ch == ‘\n‘); if (ch == ‘-‘) { *p = -(getchar() - ‘0‘); while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 - ch + ‘0‘; } } else { *p = ch - ‘0‘; while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 + ch - ‘0‘; } } }
Comet OJ - Contest #2 B 她的想法、他的戰鬥(概率 + 數學)