1 条题解
-
0
前缀和,二分
考虑每个茶会被哪些人喝
对于第 个茶,第一轮会被第 个人喝,第二轮会被第 个人喝,第三轮... 直到茶被喝完或第 个人喝过。
结论:第 个茶会被区间 的人喝,其中 为 的最小值.
那么 的求法也非常简单,可以用二分。
此时 的人喝的值为 ,第 个人喝的值为剩下的部分。
可以用差分数组存储前者区间的部分,后者单独用数组存储。 最后统计答案即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, LL> PII; #define x first #define y second const int N = 2e5 + 10, mod = 1e9 + 7; int a[N], b[N]; LL sum[N]; LL cnt[N], d[N]; // 喝b[i]的次数,a剩余的量 void solve() { int n; cin >> n; for(int i = 1; i <= n; i ++) cnt[i] = d[i] = 0; for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= n; i ++) cin >> b[i]; for(int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + b[i]; for(int i = 1; i <= n; i ++) { if(b[i] >= a[i]) { d[i] += a[i]; continue; } int l = i, r = n; // <= a[i]的最大下标 while(l < r) { int mid = l + r + 1 >> 1; if(sum[mid] - sum[i - 1] <= a[i]) l = mid; else r = mid - 1; } cnt[i] ++, cnt[l + 1] --; d[l + 1] += a[i] - sum[l] + sum[i - 1]; } for(int i = 1; i <= n; i ++) { cnt[i] += cnt[i - 1]; cout << cnt[i] * b[i] + d[i] << ' '; } cout << endl; } int main() { int t = 1; scanf("%d", &t); while(t --) solve(); }
- 1
信息
- ID
- 197
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 12
- 已通过
- 4
- 上传者