社区讨论
暴力 80->68求调
P3826[NOI2017] 蔬菜参与者 1已保存回复 0
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mhjocmve
- 此快照首次捕获于
- 2025/11/04 05:51 4 个月前
- 此快照最后确认于
- 2025/11/04 05:51 4 个月前
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int a=0,b=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-') b=-1;
c=getchar();
}
while(isdigit(c)){
a=(a<<1)+(a<<3)+(c-'0');
c=getchar();
}
return a*b;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>=10) write(x/10);
putchar(x%10+48);
}
inline void write1(int x){
write(x),putchar(' ');
}
inline void write2(int x){
write(x),putchar('\n'); //不同的输出方式的区别
}
const int N=114514; //1e5
int n,m,k;
struct veg{
int a,s,c,x;
//a 单位收益
//s 额外收益
//c 初始库存
//x 变质速率
}sum[N];
void input(){
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++){
sum[i].a=read(),sum[i].s=read(),sum[i].c=read(),sum[i].x=read();
}
//这是输入部分 为了在先回答全部询问 先处理出所有的结果再统一回答
}
int day=3; //最晚的日子
int include13; //最终的答案 用 include13 数组来表示
int include13_fAKe[N]; //原先的方案不可行了
struct node1{
int id; //目前的种类
int val; //价值
friend bool operator <(node1 a,node1 b){
return a.val<b.val; //要把价值较大的排在前面
//选大根堆恰好就要反着来
}
};
priority_queue<node1> q1; //第一种序列 存储最开始的结果
int sold_sum[N]; //卖出的数量
int atime[N]; //appear time 存储第一次出现的时间
//很多题解中都提到了关于如何处理出现时间的方法
vector<int> app1[N]; //代表新插入的蔬菜种类
void q1_init(){
for(int i=1;i<=n;i++){
//首先处理 atime 处理出一个 vector 即可
if(sum[i].x==0){
atime[i]=day; //代表永不变质
}
else{
int day1=sum[i].c/sum[i].x;
if(sum[i].c%sum[i].x) day1++;
atime[i]=min(day,day1); //考虑首先处理出来在哪一天
}
}
for(int i=1;i<=n;i++){
//把所有的内容在一个新的 for 循环中共同处理 防止混乱
int now=atime[i];
app1[now].push_back(i); //一种新的情况
}
}
queue<node1> q; //考虑在执行完一轮操作之后用这个 queue 回收有用的节点
//可实现 “持久化” 的队列
void solve1(){
q1_init();
for(int i=day;i>=1;i--){
//首先要正确处理目前的情况
for(int j=app1[i].size()-1;j>=0;j--){
node1 new_; //在这里定义一个新的结构体
int now=app1[i][j]; //这是目前的 id 编号
new_.id=now; //直接锁定 now
new_.val=sum[now].a+sum[now].s; //计算最新的 val
q1.push(new_); //将 node1 放进队列
// cout<<'&'<<new_.id<<' '<<new_.val<<endl;
} //事实证明:在一段队列中
int lim=m; //目前的限制
while(lim&&!q1.empty()){
node1 now=q1.top();
q1.pop();
int id=now.id;
int val=now.val; //现在要考虑 是否有两种情况
// cout<<"!"<<id<<' '<<val<<endl;
if(!sold_sum[id]){
//第一种情况:要考虑增加价值
include13+=val; //先加上这个值
sold_sum[id]++; //代表目前的情况可以往前增加对应的值
// cout<<'#'<<id<<' '<<val<<' '<<1<<' '<<include13<<endl;
node1 rec; //recycle 区
rec.id=id;
rec.val=sum[id].a; //这个时候就没有先发性的优势了
lim--; //代表这里就没有值了
if(sold_sum[id]!=sum[id].c){
q1.push(rec); //注意不是任何时候都可以这么操作
}
// cout<<'#'<<id<<' '<<val<<' '<<1<<' '<<include13<<' '<<lim<<endl;
}
else{
//定义一共能去除 sum1 个
int sum1=min(lim,sum[id].c-(i-1)*sum[id].x-sold_sum[id]); //一起在 sum1 计算总数
include13+=val*sum1; //这里的计算略显复杂
// cout<<'#'<<id<<' '<<val<<' '<<sum1<<' '<<include13<<endl;
sold_sum[id]+=sum1;
node1 rec;
lim-=sum1;
rec.id=id,rec.val=sum[id].a;
if(sold_sum[id]!=sum[id].c){
q.push(rec); //重新把这些数插进来
}
// cout<<'#'<<id<<' '<<val<<' '<<sum1<<' '<<include13<<' '<<lim<<endl;
}
}
// while(!q1.empty()){
// node1 now=q1.top();
// q1.pop();
// cout<<'!'<<now.id<<' '<<now.val<<endl;
// }
//这只是检测步骤
while(!q.empty()){
node1 now2=q.front();
q.pop();
q1.push(now2);
}
// cout<<endl;
}
write2(include13);
// cout<<include13<<endl;
while(!q1.empty()) q1.pop();
for(int i=1;i<=n;i++){
sold_sum[i]=0;
while(app1[i].size()) app1[i].pop_back();
}
}
signed main(){
input();
// day=1;
// solve1(); //首先处理出最大天数的情况
// include13=0;
// day=3;
// solve1();
while(k--){
day=read();
solve1();
include13=0;
}
} //能够从入门那一天待到现在,早已是奇迹了吗?
forest114514
回复
共 0 条回复,欢迎继续交流。
正在加载回复...