帶精度問題的二分的方法 Voltage Keepsake CodeForces - 801C (思維+二分)
阿新 • • 發佈:2019-01-08
Voltage Keepsake CodeForces - 801C (思維+二分)
本博以這題為原型,分析兩種常用的帶精度問題的二分方法
第一種,常見二分模型:
while(r-l>eps) { mid=(r+l)/2.00000; if(check(mid)) { l=mid; ans=l; }else { r=mid-eps; } }
用這種模型的話,首先要根據題目確定出正確的eps,然後注意要在checkmid值後,如果滿足條件,用一個double ans的額外變數被儲存每一次符合條件的值,到最後我們要找的答案就是ans,
然後注意二分的用法,L每一次賦值為mid,而R每一次要賦值為mid-eps,如果不減去eps,有時候這個while二分會進入一個死迴圈。
第二種模型,對精度問題就好解決,
for(int i=1;i<=200;i++) { mid=(r+l)/2.00000; if(check(mid)) { l=mid; ans=l; }else { r=mid; } }
根據題目資料來直接敲定一共最多二分多少次,根據精度到多少位或者二分的上屆最大值,
一般預設二分100次和200次就空可以滿足題目的精度和邊界問題,
具體為什麼可以滿足,我們可以這樣思考,如果上屆很大,也不會比2^200次方大吧,如果精度要求很高,那麼1/eps (即eps的倒數,如果要求1e-5的精度,就是1e5)也不會比2^200大
親測上邊界位1e10,精度位1e-4的題目可以用50次就AC,
附上上面那個題目的兩種程式碼
第一種:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #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 std::ios::sync_with_stdio(false) #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 gg(x) getInt(&x) #define eps 1e-6 using namespace std; typedef long long ll; inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ struct node { int h; int x; }a[maxn]; int n,p; bool check(double mid) { double need=0.0000; double sum=0.00000; repd(i,1,n) { need=mid*a[i].x-a[i].h; if(need>0.0000000) { sum+=need; }else { } } return 1.000000*mid*p-sum>0.000000; } int main() { gg(n),gg(p); ll sum=0ll; repd(i,1,n) { gg(a[i].x); gg(a[i].h); sum+=(1ll*a[i].x); } if(sum<=p) { printf("-1\n"); }else { double l=0.0000; double r=1e10; double mid; double ans; while(r-l>eps) { mid=(r+l)/2.00000; if(check(mid)) { l=mid; ans=l; }else { r=mid-eps; } } printf("%.5lf\n", ans); } 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'; } } }View Code
第二種:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #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 std::ios::sync_with_stdio(false) #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 gg(x) getInt(&x) #define eps 1e-6 using namespace std; typedef long long ll; inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ struct node { int h; int x; }a[maxn]; int n,p; bool check(double mid) { double need=0.0000; double sum=0.00000; repd(i,1,n) { need=mid*a[i].x-a[i].h; if(need>0.0000000) { sum+=need; }else { } } return 1.000000*mid*p-sum>0.000000; } int main() { gg(n),gg(p); ll sum=0ll; repd(i,1,n) { gg(a[i].x); gg(a[i].h); sum+=(1ll*a[i].x); } if(sum<=p) { printf("-1\n"); }else { double l=0.0000; double r=1e10; double mid; double ans; for(int i=1;i<=200;i++) { mid=(r+l)/2.00000; if(check(mid)) { l=mid; ans=l; }else { r=mid; } } printf("%.5lf\n", ans); } 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'; } } }View Code