[NOI2017]蔬菜(贪心)

神仙题啊!

早上开了两个多小时,终于肝出来了,真香

我们考虑从第 (10^5) 天开始递推,先生成 (p=10^5) 的解,然后逐步推出 (p-1,...,2,1) 的解。

那怎么推出 (p=10^5) 的解呢?

现在将题目转化成不停进货然后取 (m) 个最大的问题,然后删除最大并 (push) 进去。这我们可以想到大根堆。

但是由于政策 增加题目难度,有一个 (s)。我们需要先将 ((a_i+s_i,i)) (push) 进去,然后用掉了以后将 ((a_i,i)) (push) 进去。

因为在第 (i) 天买了一种蔬菜,当天就无需再用,我们考虑用一个栈存储一下当天用了不是 (a+s) 的蔬菜,

然后 (p=10^5) 的解生成完了以后,现在就是生成其他解了。

我们每次将最小的 (sum-i*m) 个取出然后删除。此时我们也要特判政策。

答案要开 (long long),时间复杂度 (O(pmlog n))

(Code Below:)

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define F first
#define S second
using namespace std;
const int maxn=100000+10;
const int lim=100000;
int n,m,k,a[maxn],s[maxn],c[maxn],x[maxn],used[maxn],sum,top;
vector<int> v[maxn];ll ans[maxn];pii sta[maxn];
priority_queue<pii> pq;

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

int main()
{
	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) v[lim].push_back(i);
		else v[(c[i]+x[i]-1)/x[i]].push_back(i);
	}
	pii u;int rest;
	for(int i=lim;i>=1;i--){
		for(int j=0;j<v[i].size();j++) pq.push(mp(a[v[i][j]]+s[v[i][j]],v[i][j]));
		for(int j=m;j>=1&&!pq.empty();){
			u=pq.top(),pq.pop();
			if(!used[u.S]){
				used[u.S]++;ans[lim]+=u.F;j--;
				if(used[u.S]!=c[u.S]) pq.push(mp(a[u.S],u.S));
			}
			else {
				rest=min(j,c[u.S]-used[u.S]-(i-1)*x[u.S]);
				ans[lim]+=(ll)rest*a[u.S];used[u.S]+=rest;j-=rest;
				if(used[u.S]!=c[u.S]) sta[++top]=mp(a[u.S],u.S);
			}
		}
		while(top) pq.push(sta[top--]);
	}
	while(!pq.empty()) pq.pop();
	for(int i=1;i<=n;i++) sum+=used[i];
	for(int i=1;i<=n;i++){
		if(used[i]==1) pq.push(mp(-a[i]-s[i],i));
		else if(used[i]) pq.push(mp(-a[i],i));
	}
	for(int i=lim-1;i>=1;i--){
		ans[i]=ans[i+1];
		while(sum>i*m&&!pq.empty()){
			u=pq.top(),pq.pop();u.F=-u.F;
			if(used[u.S]==1) ans[i]-=u.F,sum--,used[u.S]=0;
			else {
				rest=min(sum-i*m,used[u.S]-1);
				sum-=rest;used[u.S]-=rest;ans[i]-=(ll)rest*a[u.S];
				if(used[u.S]==1) pq.push(mp(-a[u.S]-s[u.S],u.S));
				else pq.push(mp(-a[u.S],u.S));
			}
		}
	}
	while(k--) printf("%lld
",ans[read()]);
	return 0;
}
原文地址:https://www.cnblogs.com/owencodeisking/p/10253806.html