D. Berland Fair (暴力出奇迹 + 时间复杂度证明)
题目:传送门
题意:有 n 个糖果,第 i 个糖果卖 ai 块钱,你现在有 T 块钱,你每次都从第一块糖果开始看,如果你的钱数够买当前的糖果,那么你就会花钱买它,如果你看完了所有 n 块糖果,那么你会从 1 重新开始看,直到你的钱数小于最便宜的糖果的价格。
1 <= n <= 2e5, 1 <= ai <= 1e9, 1 <= T <= 1e18
思路:直接暴力就行了。 最多跑 logT 次 for,那时间复杂度才 o(n*logT) 完全可接受。
关于复杂度的证明:
设 C 为这一轮能买的糖果的总价格, Tcur 为这一轮之前剩下的钱, Tnew 为买完这一轮剩下的钱。
Tnew = Tcur % C, 故 Tnew < C 且 Tnew < Tcur - C, 那 Tnew < Tcur / 2
那这样每次都至少缩小一倍, 那就最多 logT 次。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX #define PI acos(-1) using namespace std; const int N = 1e6 + 5; LL a[N]; void solve() { int n; LL T; scanf("%d", &n); scanf("%lld", &T); LL mi = INF; rep(i, 1, n) { scanf("%lld", &a[i]); mi = min(mi, a[i]); } LL ans = 0; while(T >= mi) { LL sum = 0; LL c = 0; rep(i, 1, n) { if(T >= a[i]) { sum += a[i]; T -= a[i]; ans++; c++; } } LL tmp = T / sum; ans = ans + tmp * c; T %= sum; } printf("%lld\n", ans); } int main() { solve(); return 0; }
一步一步,永不停息