[NOI2017] 蔬菜 题解
神仙贪心题,我这种蒟蒻只能写一篇题解来
思路#
很容易发现,我们做这道题时,正着去递推贪心及其困难。
尤其还有一些过期等限制,解决起来及其复杂。
那么我们就能有一个小小的思路:时光倒流。
我们从反着来递推贪心。
可以发现,过期这个限制就变成了出现。
是不是瞬间就简单多了。
实现步骤#
首先有一个大致的步骤:
-
算出第十万天的答案。
-
不断往前递推,算出前面所有的贡献,列出答案表。
-
最后
查询答案
我们可以从
首先要记录每个时刻出现那些菜,可以用
我们考虑将每一个时刻选的的菜用优先队列来维护。
一开始从
因为它是第一次出现。
然后,在循环过程中,每次拿出堆顶最大的值。
我们同样还要记录这个菜有没有被选过。
如果拿出的菜没有被选过,就可以直接把这一个记录答案,剩下的直接以
如果拿出的菜被选过了,就能取多少取多少。
注意上述过程的答案全部都是给第十万天加的贡献。
递推非常简单。
每次删掉贡献最少的菜就可以了。
Code#
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 100010;
int n , m , k , a[maxn] , s[maxn] , c[maxn] , x[maxn] , ans[maxn];
int p = 100000 , now , sum[maxn] , used[maxn];
queue<pair<int , int> > r;
vector<int> l[maxn];
priority_queue< pair<int , int> > q;
priority_queue< pair<int , int> , vector<pair<int , int> > , greater< pair<int , int> > > q2;
inline int read()
{
int asd = 0 , qwe = 1; char zxc;
while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
return asd * qwe;
}
signed main()
{
// freopen("1.in" , "r" , stdin);
// freopen("1.out" , "w" , stdout);
n = read() , m = read() , k = read();
for(int i = 1;i <= n;i++)
{
a[i] = read() , s[i] = read() , c[i] = read() , x[i] = read();
if(x[i] == 0) l[p].push_back(i);
else l[min(p , (c[i] + x[i] - 1) / x[i])].push_back(i);
}
for(int i = p;i >= 1;i--)
{
for(auto j : l[i]) q.push(make_pair(a[j] + s[j] , j));
if(q.empty()) continue;
for(int tim = m;tim >= 1 && q.empty() == 0;q.pop())
{
int top = q.top().second;
// cout << top << " " << tim << " " << used[top] << " " << a[top] << " " << s[top] << " " << i << " " << ans[p] << endl;
if(used[top] == 0)
{
tim--;
ans[p] += (a[top] + s[top]) , sum[top]++ , used[top] = 1;
if(sum[top] != c[top]) q.push(make_pair(a[top] , top));
}
else
{
int last = c[top] - (i - 1) * x[top] - sum[top];
int del = min(last , tim);
ans[p] += del * a[top] , sum[top] += del , tim -= del;
if(sum[top] != c[top]) r.push(make_pair(a[top] , top));
}
}
while(!r.empty()) q.push(r.front()) , r.pop();
}
for(int i = 1;i <= n;i++)
{
now += sum[i];
if(sum[i] == 1) q2.push(make_pair(a[i] + s[i] , i));
else if(sum[i] > 1) q2.push(make_pair(a[i] , i));
}
for(int i = p - 1;i >= 1;i--)
{
ans[i] = ans[i + 1];
int can_del = now - i * m;
while(can_del > 0)
{
int top = q2.top().second; q2.pop();
if(sum[top] == 1)
{
ans[i] -= (a[top] + s[top]);
can_del-- , now--;
}
else
{
int del = min(can_del , sum[top] - 1);
ans[i] -= a[top] * del;
can_del -= del , sum[top] -= del , now -= del;
if(sum[top] > 1) q2.push(make_pair(a[top] , top));
else if(sum[top] == 1) q2.push(make_pair(a[top] + s[top] , top));
}
}
}
for(int i = 1;i <= k;i++)
{
int x = read();
cout << ans[x] << endl;
}
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/15905086.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)