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;
}

猜你喜欢

转载自www.cnblogs.com/Willems/p/12388407.html