POJ 3737 UmBasketella
推導之後發現,體積先增後減,所以我們三分。
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <string>
#define For(i, j, n) for (int i = j; i <= n; ++i)
const double pi = acos(-1.0);
const double eps = 1e-9;
double S; // 表面積
double r, h; // 半徑和高
double l; // 母線長
double GetVolume(const double &r) {
l = (S - r * r) / r;
h = sqrt(l * l - r * r);
return pi * r * r * h / 3.0;
}
inline double TernarySearch() {
double leftBound = 0.0, rightBound = sqrt(S/2);
double V1, V2, m1, m2;
while (rightBound - leftBound > eps) {
double gap = (rightBound - leftBound) / 3.0;
m1 = leftBound + gap, m2 = rightBound - gap;
V1 = GetVolume(m1), V2 = GetVolume(m2);
if (V1 > V2) {
rightBound = m2;
} else {
leftBound = m1;
}
}
r = rightBound;
return GetVolume(r);
}
int main() {
while (~scanf("%lf", &S)) {
S /= pi;
double ans = TernarySearch();
printf("%.2f\n%.2f\n%.2f\n", ans, h, r);
}
return 0;
}
key points 1. 輸出佔位符影響正確性
這道題玄學的地方在於,最後輸出的時候用%.2lf
無法透過,換成%.2f
才行,針對此問題,GPT是這樣解釋的:
這是一個 浮點數輸出格式要求的問題。在一些競賽平臺或線上評測系統上(如 POJ),輸出格式必須嚴格符合題目要求,哪怕是小數位數的差異都會導致 Wrong Answer。讓我們詳細分析為什麼 %.2f
可以透過,而 %.2lf
不能。
%.2f
vs. %.2lf
區別
1. 格式說明符解釋
%f
是用於格式化float
/double
型別的輸出格式符。- 在
printf
中:%f
:用於輸出float
和double
型別的小數。%lf
:也是用於double
,但它的使用與scanf
更相關。
2. 為什麼 %.2lf
導致錯誤?
printf
實際上不區分%f
和%lf
,在 C 標準中,printf
中使用%f
即可處理所有float
和double
資料。因此,%.2lf
雖然語法上不會出錯,但它可能會導致輸出與題目嚴格要求不符。
3. 競賽系統的嚴格格式檢查
- 有些競賽平臺會嚴格匹配 輸出格式,包括空格、換行符和小數位數的格式。
- 在這個問題中,題目要求兩位小數。
%.2f
輸出格式符合這個要求。%.2lf
雖然語法正確,但它可能在底層儲存或匹配時與題目要求存在微小差異,導致評測系統判定為 Wrong Answer。
正確使用的總結
- 在
printf
中,只需要使用%f
即可處理float
和double
,不必使用%lf
。 - 在
scanf
中,%lf
是必要的,因為它用於區分double
和float
輸入:double x; scanf("%lf", &x); // 必須使用 %lf 來讀取 double 型別
如何避免類似問題?
- 始終使用
%.2f
處理浮點數輸出,避免多餘的格式化問題。 - 確保輸出與題目要求完全一致,包括小數位數、空格和換行符。
總結
%.2lf
在printf
中並不會影響程式的執行,但可能與題目的嚴格格式檢查不符。- 使用
%.2f
是更好的選擇,因為這是標準的浮點數格式化輸出方法,能確保與評測系統的要求一致。
key points 2.cin cout取消繫結加速&指定小數位數
在 C++ 中,std::cout
可以透過一些格式化設定來指定 小數位數,並且透過取消與 C 風格 I/O 的同步來加速輸出。下面詳細說明這些操作。
1. 使用 std::cout
指定小數位數
方法:std::fixed
和 std::setprecision
std::fixed
:指定使用定點表示法(而不是科學計數法)。std::setprecision(n)
:指定要保留的小數位數。
示例程式碼:指定兩位小數
#include <iostream>
#include <iomanip> // 需要引入 iomanip 標頭檔案
int main() {
double value = 3.141592653589793;
std::cout << std::fixed << std::setprecision(2);
std::cout << "Value: " << value << std::endl;
return 0;
}
輸出:
Value: 3.14
說明:
std::fixed
:確保輸出為 定點小數。std::setprecision(2)
:設定保留 2 位小數。- 如果沒有
std::fixed
,std::cout
可能會根據數值大小使用 科學計數法。
2. 加速 std::cout
:取消繫結同步
預設同步導致效能問題
- 預設情況下,
std::cout
和 C 標準庫的printf
是同步的,以確保兩者輸出不會交錯。這種同步機制會降低輸出速度。
如何取消同步來加速輸出?
透過以下程式碼可以取消這種同步,提高 std::cout
的效能:
示例程式碼:取消同步
#include <iostream>
#include <iomanip> // 如果需要格式化輸出
int main() {
std::ios::sync_with_stdio(false); // 取消 C I/O 和 C++ I/O 的同步
std::cin.tie(0); // 取消 cin 和 cout 的繫結
double value = 3.14159;
std::cout << std::fixed << std::setprecision(2);
std::cout << "Value: " << value << std::endl;
return 0;
}
說明:
-
std::ios::sync_with_stdio(false);
- 取消 C 和 C++ I/O 的同步,使得
std::cout
輸出速度更快。 - 注意:如果你還使用
printf
或其他 C 風格 I/O 函式,可能會出現輸出交錯問題。
- 取消 C 和 C++ I/O 的同步,使得
-
std::cin.tie(0);
- 取消
std::cin
和std::cout
的繫結。預設情況下,std::cin
每次讀取時會自動重新整理std::cout
,取消繫結後可以進一步提升效能。
- 取消
加速效果對比
- 未取消同步:處理大量資料輸出時,
std::cout
速度會較慢。 - 取消同步:速度提升明顯,尤其在 演算法競賽或需要快速 I/O 的場合。
總結
- 指定小數位數:使用
std::fixed
和std::setprecision
。 - 加速
std::cout
輸出:- 使用
std::ios::sync_with_stdio(false);
取消 C 和 C++ I/O 的同步。 - 使用
std::cin.tie(0);
取消輸入輸出的繫結。
- 使用
這些方法在處理大量資料時會顯著提升效能,同時格式化輸出也會更加靈活。
並且經過嘗試,發現這道題用cout來固定位數也是可以透過的。