原题:Kabaleo Lite
题面:
思路:
本题需要注意的是数据范围,可能会达到
±
1
e
19
\pm1e^{19}
±1e19。用ULL可以处理正数,LL处理负数?不知道,我不会,我太菜了。普遍用
i
n
t
128
int128
int128 处理数据。
我们可以先预处理出
p
r
o
f
i
t
profit
profit 的前缀和,以及每一道菜会被用的次数。第
i
i
i 道菜的选择次数是由它的前继菜品的最小数量和它的数量构成的,也就是:
c
n
t
[
i
]
=
m
i
n
(
c
n
t
[
i
−
1
]
,
b
[
i
]
)
cnt[\ i\ ]=min(cnt[\ i -1\ ], b[\ i\ ])
cnt[ i ]=min(cnt[ i−1 ],b[ i ])
我们还可以筛选一下可用的前缀和。当某一个前缀和小于
a
[
i
]
a[\ i\ ]
a[ i ] 的时候,这个选择方案一定不是最优解(明明能选一个
1
1
1 能解决的事儿,为什么要选那么多个呢?),所以我们可以把
s
u
m
[
i
]
≥
a
[
1
]
sum[\ i\ ] \ge a[\ 1\ ]
sum[ i ]≥a[ 1 ] 的前缀和存到一个数组进去。
最后需要一点点贪心的思想,将可选用的数组以前缀和从大到小排序。能选就选。最后就是我们要的答案啦。
这里我顺便存了一下每一个前缀和到达的右端点,是为了更新选择的次数啦。
代码如下:
#include <bits/stdc++.h>
#define sc scanf
#define pf printf
using namespace std;
typedef long long LL;
typedef pair<__int128, int> PII;
const int N = 1e5 + 10;
int t, n, cnt[N], pre_cnt, b[N], a[N];
__int128 sum[N], max_profit;
vector<PII> v;
bool cmp_v(PII a, PII b)
{
if(a.first == b.first) return a.second > b.second;
return a.first > b.first;
}
//__int128的输出。
inline void print(__int128 x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
void solve(int cas)
{
sc("%d", &n);
v.clear();
memset(cnt, 0x3f, sizeof cnt);
for(int i = 1; i <= n; i++) sc("%d", &a[i]);
for(int i = 1; i <= n; i++) sc("%d", &b[i]);
//预处理前缀和,并将每个坐标能被用的次数统计一下。
//因为菜品必须从1开始选择
//所以每道菜能被选择的次数是它的前继中最少的菜品数
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1]+a[i];
cnt[i] = min(cnt[i - 1], b[i]);
}
//筛选一下符合优解可选用的前缀和
for(int i = 1; i <= n; i++)
if(sum[i] >= a[1])
v.push_back({sum[i], i});
//小贪心思想,让前缀和大的在前面
sort(v.begin(), v.end(), cmp_v);
max_profit = 0, pre_cnt = 0;
LL max_number = 0, pre_pos = n;
for(int i = 0; i < v.size(); i++) {
//如果当前前缀和可以被选择,则将它选完,并更新选择的次数和索引。
if(v[i].second <= pre_pos && cnt[v[i].second] > pre_cnt) {
max_profit += v[i].first * (cnt[v[i].second] - pre_cnt);
max_number += (cnt[v[i].second] - pre_cnt);
pre_cnt = cnt[v[i].second];
pre_pos = v[i].second;
}
}
//其实最大客流量就是b[1]。
pf("Case #%d: %lld ", cas, max_number);
print(max_profit);
puts("");
}
int main()
{
sc("%d", &t); for(int i = 1; i <= t; i++) solve(i);
return 0;
}