Loading

CF1870D Prefix Purchase 题解

CF1870D Prefix Purchase 题解

CnBlogs链接

题意

你有一个长为 \(n\) 的数组 \(a\),初始全为 \(0\)

初始你有 \(k\) 个硬币。你可以花费 \(c_i\) 个硬币让 \(a\) 数组 \([1,i]\) 的前缀的值 \(+1\)。你要保证自己的硬币数量始终非负。

\(a\) 数组的字典序最大是多少。

思路

萌新竟然能切 D 了!!!

首先考虑 dp。记 \(f_i\) 表示花费 \(i\) 个硬币时,\(a_1\) 最大是多少。但是要最大化字典序,所以我们需要尽可能选 \(i\) 较大的 \(c_i\)。所以我们记 \(g_i\) 表示 \(f_i\) 是用哪种硬币转移过来的。跑完全背包即可。复杂度 \(O(nk)\)

发现这样复杂度过于炸裂。我们考虑 dp 做的是什么,就是优先选尽可能多的 \(a_1\),然后尽可能多的选择 \(a_2\),以此类推。

考虑如何选尽可能多的 \(a_1\)。肯定是选择全局最小值啊!考虑如何选尽可能多的 \(a_2\)。肯定是用后缀最小值替换掉上面对 \(a_1\) 贡献的一些 \(c\) 啊!所以我们用堆维护已经选过的 \(c\),每次用 \(c\) 的后缀最小值去尝试替换。

复杂度 \(O(n\log n)\)

代码

萌新代码有点丑,大佬不要嫌弃

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int ans=0;bool op=0;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')op=1;ch=getchar();}
	while('0'<=ch&&ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
	if(op)return -ans;
	return ans;
}
const int maxn=2e5+10;
int n,k;
int c[maxn];
int mn[maxn];//c的后缀最小值的下标
int a[maxn];//最终形成的序列
struct node{
	int val,cnt,id;//这个c的权值、数量、编号
	bool operator < (const node &cmp)const{
		return val<cmp.val||(val==cmp.val&&id>cmp.id);
	}
};
priority_queue<node>q;
void real_main(){
	//read
	n=read();
	for(int i=1;i<=n;i++)c[i]=read();
	k=read();
	//init
	//清空
	while(!q.empty())q.pop();
	memset(a,0,sizeof(int)*(n+2));
	mn[n]=n;
	for(int i=n-1;i>=1;i--)mn[i]=c[i]<c[mn[i+1]]?i:mn[i+1];//处理后缀最小值的下标
	q.push((node){0,(int)2e9,0});//加一个0,方便处理
	//solve
	for(int i=1;i<=n;i++){
		node awa=(node){c[mn[i]],0,mn[i]};
		while(!q.empty()){
			node now=q.top();q.pop();
			int dif=c[mn[i]]-now.val;
			if(!dif){//如果不用替换,那么直接退出
				q.push(now);//拿出来的没有动,放回去
				break;
			}
			int tmp=min(k/dif,now.cnt);//计算一下可以替换掉几个
			now.cnt-=tmp;
			awa.cnt+=tmp;
			a[now.id]-=tmp;
			a[mn[i]]+=tmp;
			k-=dif*tmp;
			if(now.cnt)q.push(now);
			if(!tmp)break;//已经不能替换了,退出
		}
		if(awa.cnt)q.push(awa);
	}
	for(int i=n;i>=1;i--)a[i]=a[i+1]+a[i];//我们的a是一个后缀和,算出来
	for(int i=1;i<=n;i++)cout<<a[i]<<' ';
	puts("");
}
signed main(){
	int T=read();//多组数据
	while(T--)real_main();
	return 0;
}s
posted @ 2023-09-20 18:34  洛谷Augury  阅读(103)  评论(0)    收藏  举报