2020牛客暑期多校训练营(第八场) K
K.Kabaleo Lite
题目链接
题意:
有N个菜, 第 i 道菜有 盈利值 a[i] 和 数量 b[i] , 每次给一位客人上菜 需要从第一道菜开始上,上完第一道菜才能上第二道菜 , 上完第二道菜才能上第三道菜 ... 以此类推
问 最多能给几个客人上菜 , 在客人最大化的情况下 ,最大盈利是多少(可能为负)
想法:
① 最多可以给b[1]个客人上菜 , 因为每个客人都一定要上第一道菜
② 假如 第 5 道菜数量为 1 , 第 6 道菜数量为 100 , 那么第 6 道菜的数量可以看做 1 ,因为 第 5 道菜只能上一次 , 而第 6 道菜只能在第 5 道上过了 才能上。
③ 计算一个 a[ i ] 前缀和 pre[ i ] , 含义是:总共上 [1 ~ i ]道菜 的利润
④ 只要从后往前 , 每次找到 [1 ~ i ] 中利润最高的 pre[ i ] ,然后看数量还够不够 , 如果够 , 就全取掉 , 如果不够 , 同理继续往前找。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 10; #define ll long long #define int long long template <typename T> void read(T &res) { bool flag = false; char ch; while (!isdigit(ch = getchar())) (ch == '-') && (flag = true); for (res = ch - 48; isdigit(ch = getchar()); res = (res << 1) + (res << 3) + ch - 48) ; flag && (res = -res); } template <typename T> void Out(T x) { if (x < 0) putchar('-'), x = -x; if (x > 9) Out(x / 10); putchar(x % 10 + '0'); } int a[maxn] , b[maxn]; __int128 maxx[maxn] , pre[maxn]; signed main() { //ios; //cin.tie(0); int t; read(t); int num = 1; while(t --){ int n; read(n); for(int i = 1 ; i <= n ; i ++) read(a[i]) , pre[i] = pre[i - 1] + a[i]; for(int i = 1 ; i <= n ; i ++) read(b[i]); for(int i = 2 ; i <= n ; i ++) b[i] = min(b[i] , b[i - 1]); int pos = 1; maxx[1] = pos; for(int i = 2 ; i <= n ; i ++){ if(pre[i] > pre[pos]){ maxx[i] = i , pos = i; } else maxx[i] = maxx[i - 1]; } __int128 ans = 0 , cnt = 0; for(__int128 i = n ; i >= 1 ; i --){ __int128 now = maxx[i]; if(cnt >= b[now])continue; ans += (b[now] - cnt) * pre[now]; cnt += (b[now] - cnt); } cout << "Case #" << num ++ << ": " << b[1] << ' '; Out(ans); cout << '\n'; } return 0; }