社区讨论

暴力 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 条回复,欢迎继续交流。

正在加载回复...