ABC258E
传送门:$ \sum _{i = 1} ^{n} a_i $
话说回来最近没咋更博呀。
进入正题
有无穷多个土豆,这些土豆的重量是循环的。
每次我们装到框里,但如果重量总和不小于X,就准备一个新框。
问第K个框装了多少个土豆。
思路
Level 1
首先我们知道,到了后期土豆的装框数量是会循环的。
于是我们可以准备一个数组来存储后期循环情况。
但是前面不循环的怎么办?
Level 2
直接上结论:n个框以内一定会踏入循环。别问我为什么
接着就是统计每个框以及循环框里都有多少个土豆了。
但是,枚举和是O(n)的,枚举一部分也不例外。
我们可以用前缀和,但是时间复杂度还是O(n)。有O(log n)或O(1)的解法吗?
Level 3
你或许想到了,前缀和加二分查找!
这种情况下能二分最后一个土豆是哪个,时间复杂度————O(log n)。
有时候会出现跨轮的情况,这怎么办?
直接把数组复制一遍再前缀和不就得了!
Level 4
只差一点了。有时候把n个全装进一个框里都不够!
再次利用循环,想一想?
答对了!n / sum * n!
Level Boss
到了最终写代码的时刻了。
不行的话过来跳关。
#include <cstdio>
#include <algorithm>
using namespace std;
#define error_log printf
int w[400005];
long long pre[400005];
long long ans0[400005], ans1[400005];
int main() {
int n;
int q;
long long x;
scanf("%d", &n);
scanf("%d", &q);
scanf("%lld", &x);
long long s = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &w[i]);
s += w[i];
w[i + n] = w[i];
}
pre[0] = w[0];
for (int i = 1; i < 2 * n; i++) {
pre[i] = pre[i - 1] + w[i];
}
int k = 0;
for (int i = 0; i < n; i++) {
ans0[i] = x / s * n;
int y = x % s == 0 ? k - 1 : lower_bound(pre + k, pre + 2 * n, ((k == 0) ? (0) : (pre[k - 1])) + x % s) - pre;
ans0[i] += y - k + 1;
k = (y + 1) % n;
}
int u = k;
int rep_cnt = 0;
while (1) {
ans1[rep_cnt] = x / s * n;
int y = x % s == 0 ? k - 1 : lower_bound(pre + k, pre + 2 * n, ((k == 0) ? (0) : (pre[k - 1])) + x % s) - pre;
ans1[rep_cnt++] += y - k + 1;
k = (y + 1) % n;
if (k == u) {
break;
}
}
while (q--) {
long long k;
scanf("%lld", &k);
k--;
printf("%d\n", (k < n) ? (ans0[k]) : (ans1[(k - n) % rep_cnt]));
}
return 0;
}
后续
你打过了眼前的这个小Boss,但是,还有更大的Boss像你袭来!
敬请期待下期————《ABC258G————披着G题衣服的D题》!