update
This commit is contained in:
parent
28022bb787
commit
88b9888340
@ -1,20 +1,44 @@
|
|||||||
#include <cstdint>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
using ll = int64_t;
|
using ll = long long;
|
||||||
|
|
||||||
ll n,k;
|
int main() {
|
||||||
std::vector<ll> a;
|
ll n, k;
|
||||||
|
scanf("%lld %lld", &n, &k);
|
||||||
int main(){
|
vector<ll> a(n);
|
||||||
scanf("%ld%ld",&n,&k);
|
for (int i = 0; i < n; i++) {
|
||||||
a.resize(n+1);
|
scanf("%lld", &a[i]);
|
||||||
for(ll i=1;i<=n;i++){
|
|
||||||
scanf("%ld",&a[i]);
|
|
||||||
}
|
}
|
||||||
std::vector<ll> vk(k+1);
|
|
||||||
for(ll i=1;i<=k;i++){
|
if (k > n) {
|
||||||
|
printf("0.00\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(a.begin(), a.end());
|
||||||
|
vector<double> p(n + 1, 0.0);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
p[i + 1] = p[i] + a[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
double l = 0.0, r = 1e14;
|
||||||
|
for (int iter = 0; iter < 100; iter++) {
|
||||||
|
double mid = (l + r) / 2.0;
|
||||||
|
auto it = lower_bound(a.begin(), a.end(), mid);
|
||||||
|
int pos = it - a.begin();
|
||||||
|
|
||||||
}
|
double sum = p[pos] + (n - pos) * mid;
|
||||||
|
if (sum >= k * mid) {
|
||||||
|
l = mid;
|
||||||
|
} else {
|
||||||
|
r = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double ans = (l + r) / 2.0;
|
||||||
|
printf("%.2f\n", ans);
|
||||||
|
return 0;
|
||||||
}
|
}
|
148
src/7/20/T635779.md
Normal file
148
src/7/20/T635779.md
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
你的代码试图通过模拟风火轮的使用过程来求解最大时长,但存在几个关键问题:
|
||||||
|
|
||||||
|
### 问题分析
|
||||||
|
1. **错误的理解问题**:题目要求的是同时使用k个风火轮的**最大连续时长**,而不是累计使用时间。你的代码模拟了分段使用风火轮的过程,计算的是所有时间段的总和,这不符合题目要求。
|
||||||
|
2. **模拟方法错误**:你的模拟过程(每次取出最小值,累计时间,然后更新集合)实际上计算的是所有风火轮分段使用时的总时间,而不是同时使用k个风火轮的最大连续时长。
|
||||||
|
3. **输出格式问题**:题目要求结果四舍五入保留2位小数,但你的代码直接输出`float(ans)`,没有进行格式化输出。
|
||||||
|
|
||||||
|
### 正确方法
|
||||||
|
问题本质是求最大时间t,使得满足:
|
||||||
|
```
|
||||||
|
∑ min(a_i, t) ≥ k * t
|
||||||
|
```
|
||||||
|
其中:
|
||||||
|
- 当风火轮时长a_i ≥ t时,贡献为t
|
||||||
|
- 当a_i < t时,贡献为a_i
|
||||||
|
|
||||||
|
这可以通过**二分答案**解决:
|
||||||
|
1. 对风火轮时长数组排序
|
||||||
|
2. 计算前缀和数组
|
||||||
|
3. 二分查找最大t值
|
||||||
|
4. 对于每个mid,用前缀和快速计算∑ min(a_i, mid)
|
||||||
|
|
||||||
|
### 修复后的代码
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cctype>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
using ll = long long;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ll n, k;
|
||||||
|
scanf("%lld %lld", &n, &k);
|
||||||
|
vector<ll> a(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
scanf("%lld", &a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果k > n,无法同时使用k个风火轮
|
||||||
|
if (k > n) {
|
||||||
|
printf("0.00\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(a.begin(), a.end());
|
||||||
|
vector<double> pref(n + 1, 0.0);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
pref[i + 1] = pref[i] + a[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
double l = 0.0, r = 1e14;
|
||||||
|
for (int iter = 0; iter < 100; iter++) {
|
||||||
|
double mid = (l + r) / 2.0;
|
||||||
|
// 找到第一个大于等于mid的位置
|
||||||
|
auto it = lower_bound(a.begin(), a.end(), mid);
|
||||||
|
int pos = it - a.begin();
|
||||||
|
|
||||||
|
double total = pref[pos] + (n - pos) * mid;
|
||||||
|
if (total >= k * mid) {
|
||||||
|
l = mid;
|
||||||
|
} else {
|
||||||
|
r = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double ans = (l + r) / 2.0;
|
||||||
|
printf("%.2f\n", ans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键改进说明
|
||||||
|
1. **二分答案**:使用二分查找确定最大连续时长t
|
||||||
|
2. **前缀和优化**:
|
||||||
|
- 对排序后的数组计算前缀和
|
||||||
|
- 对于每个mid值:
|
||||||
|
- 使用`lower_bound`找到第一个≥mid的位置
|
||||||
|
- 小于mid的部分直接取原值(前缀和)
|
||||||
|
- ≥mid的部分取mid值
|
||||||
|
3. **边界处理**:当k>n时直接输出0.00
|
||||||
|
4. **精度控制**:二分迭代100次保证精度
|
||||||
|
5. **正确输出**:使用`%.2f`格式输出,自动四舍五入
|
||||||
|
|
||||||
|
这个解法时间复杂度为O(n log n + 100 log n),可以高效处理最大10^5规模的数据。
|
||||||
|
|
||||||
|
为了解决这个问题,我们需要确定同时使用k个风火轮的最大时长,使得在任意时刻都有k个风火轮在转动,并且可以随时更换风火轮(更换时间忽略不计)。问题的核心在于找到一个最大的时间t,使得所有风火轮的总使用时间至少为k * t。
|
||||||
|
|
||||||
|
### 方法思路
|
||||||
|
1. **问题分析**:我们需要找到一个最大的时间t,使得所有风火轮的使用时间之和至少为k * t。每个风火轮的使用时间不能超过其自身可旋转时长,也不能超过t(因为使用时间达到t后需要更换)。
|
||||||
|
2. **关键观察**:对于给定的时间t,每个风火轮i的贡献是min(a_i, t)。因此,总使用时间是所有min(a_i, t)的和。我们需要满足sum(min(a_i, t)) ≥ k * t。
|
||||||
|
3. **二分搜索**:由于t的取值范围很大(0到最大可能值),我们使用二分搜索来高效地找到满足条件的最大t。二分搜索的每一步中,我们计算当前mid值对应的总使用时间,并与k * mid比较。
|
||||||
|
4. **优化计算**:为了快速计算sum(min(a_i, t)),我们首先对风火轮的可旋转时长数组排序,并计算前缀和。然后使用二分查找确定有多少个风火轮的时长小于mid,从而将总使用时间分为两部分:小于mid的部分直接求和,大于等于mid的部分贡献mid。
|
||||||
|
5. **边界处理**:如果k大于风火轮数量n,则不可能同时使用k个风火轮,结果直接为0.00。
|
||||||
|
|
||||||
|
### 解决代码
|
||||||
|
```python
|
||||||
|
import bisect
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import sys
|
||||||
|
data = sys.stdin.read().split()
|
||||||
|
n = int(data[0])
|
||||||
|
k = int(data[1])
|
||||||
|
a = list(map(int, data[2:2+n]))
|
||||||
|
|
||||||
|
if k > n:
|
||||||
|
print("0.00")
|
||||||
|
return
|
||||||
|
|
||||||
|
a.sort()
|
||||||
|
pref = [0] * (n+1)
|
||||||
|
for i in range(n):
|
||||||
|
pref[i+1] = pref[i] + a[i]
|
||||||
|
|
||||||
|
l, r = 0.0, 10**14
|
||||||
|
|
||||||
|
for _ in range(100):
|
||||||
|
mid = (l + r) / 2.0
|
||||||
|
p = bisect.bisect_left(a, mid)
|
||||||
|
total = pref[p] + (n - p) * mid
|
||||||
|
if total >= k * mid:
|
||||||
|
l = mid
|
||||||
|
else:
|
||||||
|
r = mid
|
||||||
|
|
||||||
|
ans = (l + r) / 2.0
|
||||||
|
print("{:.2f}".format(ans))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码解释
|
||||||
|
1. **输入处理**:读取输入数据,包括风火轮数量n、需要同时使用的风火轮数量k,以及每个风火轮的可旋转时长列表a。
|
||||||
|
2. **边界检查**:如果k大于n,直接输出0.00,因为无法同时使用k个风火轮。
|
||||||
|
3. **排序和前缀和**:对风火轮的可旋转时长列表进行排序,并计算前缀和数组pref,用于快速计算子数组的和。
|
||||||
|
4. **二分搜索**:
|
||||||
|
- 初始化二分边界l为0.0,r为一个较大的值(如1e14)。
|
||||||
|
- 迭代100次,每次计算中点mid = (l + r) / 2.0。
|
||||||
|
- 使用二分查找确定第一个大于等于mid的位置p,计算总使用时间:小于mid的风火轮贡献其自身时长,大于等于mid的风火轮贡献mid。
|
||||||
|
- 根据总使用时间是否满足k * mid调整二分边界。
|
||||||
|
5. **输出结果**:二分结束后,计算中点值作为答案,并保留两位小数输出。
|
||||||
|
|
||||||
|
这种方法高效地利用二分搜索和前缀和,在O(n log n + 100 log n)的时间复杂度内解决问题,适用于大规模数据。
|
Loading…
Reference in New Issue
Block a user