CF1070C 云计算
1 CF1070C 云计算
2 题目描述
\(Buber\) 在 \(Berland\) 科技公司专门从事浪费投资者资金的工作。最近,\(Buber\) 决定把公司的信息基础设施转移到云上。公司决定在云上连续 \(n\) 天租用 \(CPU\),编号从 \(1\) 到 \(n\)。\(Buber\)每天需要 \(k\) 个 \(CPU\) 核心。
云计算供应商提供 \(m\) 个报价单,第 \(i\) 个报价单如下:
- \(l_i\) 和 \(r_i\) - 第 \(i\) 个报价只有 \(l_i\) 和 \(r_i\) 期间有效,包括 \(l_i\) 和 \(r_i\);
- \(c_i\) - 在第 \(i\) 个报价单里每天可用的 \(CPU\) 个数;
- \(p_i\) - 在第 \(i\) 个报价单里每个 \(CPU\) 每天的价格。
\(Buber\) 可以在各个报价单上任意分配 \(CPU\)。每天 \(Buber\) 可以租用任意数量的核心(从 \(0\) 到 \(c_i\))。每天租用的 \(CPU\) 核心个数可以任意选择。
计算 \(Buber\) 租用从 \(1\) 到 \(n\) 总共 \(n\) 天的最小花费。如果某天所有可用的 \(CPU\) 总数小于 \(k\),那天 \(Buber\) 只能使用能租到的 \(CPU\) 个数,否则 \(Buber\) 就租 \(k\) 个 \(CPU\)。
3 题解
我们很容易想到,租借的最优策略是价格递增地进行租借,所以我们可以先将所有的方案按照价格递增排序。排序后,这道题就变成了线段树区间修改的裸题了。我们考虑根据每一天得到的路由器个数建树。对于每一个区间,维护其最大值和最小值。每次修改中,如果我们要查询的区间的最大值加上当前方案中每天最多能借的个数仍然小于等于 \(k\),说明该区间的所有天数都可以借,答案加上 区间长度\(*\)路由器个数\(*\)路由器价格。如果该区间的最大值等于最小值,那么说明该区间的所有天可以借到的路由器个数都相同,每天借到的路由器个数就是 \(min( k -\) 区间最大值,方案中每天最多借的路由器数量 \()\)。答案就是 可以借到的路由器个数 \(*\)区间长度\(*\) 路由器价格。如果区间最小值都大于等于 \(k\),那么说明没有任何一天还需要租借。如果上述条件都不满足,我们就继续 \(pushdown\)。
4 代码(空格警告):
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6+10;
#define int long long
int n, k, m, ans;
struct seg
{
int l, r, c, p;
}a[N];
struct node
{
int l, r, maxn, minn, tag;
}t[N*4];
bool cmp(seg ax, seg ay)
{
if (ax.p == ay.p) return ax.c > ay.c;
return ax.p < ay.p;
}
void update(int p)
{
t[p].maxn = max(t[p*2].maxn, t[p*2+1].maxn);
t[p].minn = min(t[p*2].minn, t[p*2+1].minn);
}
void build(int p, int l, int r)
{
t[p].l = l;
t[p].r = r;
if (l == r)
{
t[p].minn = 0;
t[p].maxn = 0;
return ;
}
int mid = (l+r)/2;
build(p*2, l, mid);
build(p*2+1, mid+1, r);
update(p);
}
void pushdown(int p)
{
if (t[p].tag)
{
t[p*2].tag += t[p].tag;
t[p*2+1].tag += t[p].tag;
t[p*2].maxn += t[p].tag;
t[p*2].minn += t[p].tag;
t[p*2+1].maxn += t[p].tag;
t[p*2+1].minn += t[p].tag;
t[p].tag = 0;
}
}
void modify(int p, int l, int r, int d, int c)
{
if (t[p].l >= l && t[p].r <= r)
{
if (t[p].minn >= k) return ;
if (t[p].maxn + d <= k)
{
ans += (t[p].r - t[p].l + 1) * d * c;
t[p].tag += d;
t[p].minn += d;
t[p].maxn += d;
return ;
}
else if (t[p].maxn == t[p].minn)
{
ans += (t[p].r - t[p].l + 1) * min(d, k - t[p].maxn) * c;
t[p].tag += min(d, k - t[p].maxn);
t[p].minn += min(d, k - t[p].maxn);
t[p].maxn += min(d, k - t[p].maxn);
return ;
}
}
pushdown(p);
int mid = (t[p].l + t[p].r) / 2;
if (l <= mid) modify(p*2, l, r, d, c);
if (mid < r) modify(p*2+1, l, r, d, c);
update(p);
}
signed main()
{
cin >> n >> k >> m;
for (int i = 1; i <= m; i++) cin >> a[i].l >> a[i].r >> a[i].c >> a[i].p;
sort(a+1, a+m+1, cmp);
build(1, 1, n);
for (int i = 1; i <= m; i++)
{
modify(1, a[i].l, a[i].r, a[i].c, a[i].p);
}
cout << ans;
return 0;
}