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题》!

posted @ 2022-07-05 22:09  A-Problem-Solver  阅读(16)  评论(0编辑  收藏  举报