买糖果
买糖果
$n$ 个糖果店,围成一圈。
店铺按顺时针顺序从 $1$ 到 $n$ 编号,$n$ 号店铺与 $1$ 号店铺相邻。
第 $i$ 号店铺的单个糖果售价为 $a_i$ 元。
李华拿着 $T$ 元钱去购买糖果,具体购买过程如下:
- 初始时,他位于 $1$ 号店铺。
- 如果他现有的钱足够在当前店铺购买一个糖果,他就会立即购买一个糖果,否则他将不会在当前店铺购买糖果。随后,不论他是否在当前店铺购买糖果,他都会按顺时针顺序前往下一个店铺。
- 他将不断重复过程 $2$,直到剩余的钱在所有店铺都买不起糖果为止。
请问,最终李华一共购买到多少个糖果。
输入格式
第一行包含两个整数 $n,T$。
第二行包含 $n$ 个整数 $a_1,a_2, \dots ,a_n$。
输出格式
一个整数,表示一共购买到的糖果数量。
数据范围
前 $6$ 个测试点满足 $1 \leq n \leq 10$。
所有测试点满足 $1 \leq n \leq 2 \times {10}^{5}$,$1 \leq T \leq {10}^{18}$,$1 \leq a_i \leq {10}^{9}$。
输入样例1:
3 38 5 2 5
输出样例1:
10
输入样例2:
5 21 2 4 100 2 6
输出样例2:
6
解题思路
先暴力枚举算一下走一圈可以买多少糖果,如果某个糖果买不了,当前这圈买不了那么后面每一圈肯定都买不了,因此可以跳过。假设在这一圈里可以买的糖果数量是$cnt$,花费是$sum$,那么只要总钱数$T \geq sum$,那么就可以转一圈买$cnt$个糖果,直到总钱数小于$sum$为止。在总钱数小于$sum$之前每一圈都是一样的,总钱数都是减去$sum$,糖果数量加上$cnt$。一共可以转$\left\lfloor \frac{T}{sum} \right\rfloor$圈,那么一共可以买的糖果数量就是$\left\lfloor \frac{T}{sum} \right\rfloor \times cnt$,剩余的钱就是$T \% sum$。
每次计算完后都至少有一个糖果店被减去,一共有$n$个糖果店,那么最坏情况下时间复杂度为$O(n^2)$。但事实上时间复杂度为$O(n \cdot \log{T})$。因为每次$sum$都小于等于$T$,即$T$每次取模的数都小于等于$T$,这里就会有个性质,即$T \% sum < \frac{T}{2}$,也就是每转一次$T$至少除以$2$。
证明如下。如果$sum > \frac{T}{2}$,那么$T \% sum = T - sum < \frac{T}{2}$,因为此时$T$除以$sum$的商为$1$。而如果$sum \leq \frac{T}{2}$,那么$T \% sum < \frac{T}{2}$。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 int a[N]; 9 10 int main() { 11 int n; 12 LL m; 13 scanf("%d %lld", &n, &m); 14 for (int i = 0; i < n; i++) { 15 scanf("%d", a + i); 16 } 17 18 LL ret = 0; 19 while (true) { 20 LL cnt = 0, sum = 0; 21 for (int i = 0; i < n; i++) { 22 if (sum + a[i] <= m) { 23 cnt++; 24 sum += a[i]; 25 } 26 } 27 28 if (cnt == 0) break; 29 ret += m / sum * cnt; 30 m %= sum; 31 } 32 33 printf("%lld", ret); 34 35 return 0; 36 }
参考资料
AcWing 4623. 买糖果(AcWing杯 - 周赛):https://www.acwing.com/video/4445/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16757293.html