CF521D Shop

又是神秘的一题。

题意

题意就是给你 \(k\) 个技能,有 \(n\) 个可选操作,需要选 \(m\) 个操作使总和最大。

\(t\) :操作类别
\(i\) :操作对象是第几个技能
\(b\) :按 \(t\) 分3类

操作有3类:
\(t\) ==1时,把第 \(i\) 个技能变成 \(b\)
\(t\) ==2时,把第 \(i\) 个技能加上 \(b\)
\(t\) ==3时,把第 \(i\) 个技能乘上 \(b\)

解法

从局部开始思考,如果只有乘法,那就直接把 \(b\) 从大到小排序,选前 \(m\) 个就行了。再深挖一点,如果是有加法和乘法两种呢?那就考虑把加法转乘法,就是假设 \(b\) 现在是加上 \(b\) 的意思,那转为乘法就应该是 \(\frac{a_{i}+b}{a_{i}}\) (分数有点小)

最最最最最后,思考赋值的操作(就是把第 \(i\) 个技能变成 \(b\)),思考一下,就可以发现我们能把赋值转为加法,那不就完成了吗?

一点细节
1.计算顺序因改为赋值到加法到乘法,这个很好思考吧。
2.如果一个数有多次赋值操作,那就保留赋值大的(就是 \(b\) 大的),因为如果这两次都赋值,那为什么不一次就赋值最大的那个呢?而且你是把赋值转为加法,如果一个数多次赋值,那转为加法就会有一些地方会被重复加。

代码

码风极为丑陋,请勿学习!如要借用,请改成你的精美码风!

有注释版

**#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+5;

// 结构体node用于存储最终的乘法因子(包括原始乘法和转化后的加法/赋值)
struct node
{
	double x;      // 乘法因子(即操作对乘积的放大倍数)
	ll t,id;       // t:操作类型(1赋值,2加法,3乘法), id:操作编号
}e[N];

// 结构体Node用于存储最终选中的操作,用于排序输出
struct Node
{
	ll id,t;       // id:操作编号, t:操作类型
}ans[N];

// 结构体edge用于存储每个技能的加法操作(包括原始加法和转化后的赋值)
struct edge
{
	ll t,x,id;     // t:操作类型, x:加法的数值(赋值操作转化为差值), id:操作编号
};
vector<edge>c[N];  // c[i]存储技能i的所有加法操作(按数值降序使用)

ll a[N];           // 各技能的当前值(动态更新)
ll ecnt;           // 最终乘法因子数组e的元素个数
ll Max[N],Pos[N];  // Max[i]记录技能i的赋值操作中的最大值,Pos[i]记录对应操作编号
ll acnt;           // 最终选中的操作数量

// 比较函数:按乘法因子降序排序
bool cmp(node x,node y){return x.x>y.x;}
// 比较函数:按加法数值降序排序
bool cmp1(edge x,edge y){return x.x>y.x;}
// 比较函数:先按操作类型升序(1赋值,2加法,3乘法),再按编号升序
bool cmp2(Node x,Node y){if (x.t!=y.t){return x.t<y.t;} return x.id<y.id;}

signed main()
{	
	std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
	ll k,n,m; cin >>k>>n>>m;
	for (ll i=1;i<=k;i++) cin >>a[i];          // 读入各技能初始值

	// 读入n个操作
	for (ll _=1;_<=n;_++)
	{
		ll t,i,b; cin >>t>>i>>b;
		if (t==1)                               // 赋值操作
		{
			// 对于每个技能,只保留最大的赋值,因为小的赋值不如大的
			if (b>Max[i]) Max[i]=b,Pos[i]=_;
		}
		if (t==2) {c[i].push_back({t,b,_});}    // 加法操作存入对应技能的vector
		if (t==3) {e[++ecnt].x=1.0*b; e[ecnt].t=t,e[ecnt].id=_;} // 乘法操作直接存入全局数组
	}

	// 处理赋值操作:如果最大赋值比当前值大,则将其转化为一个加法(差值)
	for (ll i=1;i<=k;i++)
	{
		if (Max[i] && Max[i]>a[i]) c[i].push_back({1,Max[i]-a[i],Pos[i]}); 
	}

	// 对每个技能的加法操作(包括原始加法和转化来的赋值)按数值降序排序
	for (ll i=1;i<=k;i++)
	{
		sort(c[i].begin(),c[i].end(),cmp1);
		// 依次应用加法(按降序),每次应用后更新a[i],并将该操作转化为乘法因子存入e
		for (auto j:c[i])
		{
			int t=j.t,x=j.x,id=j.id;
			// 转化:应用此加法后,技能值变为 a[i]+x,所以乘数为 (a[i]+x)/a[i]
			e[++ecnt].x=1.0*(x+a[i])/a[i]; 
			e[ecnt].t=t;
			e[ecnt].id=id;
			a[i]+=x;    // 更新当前值,以便后续加法基于新值计算乘数
		}
	 } 

	// 将所有乘法因子(包括原始乘法和转化后的加法)按降序排序
	sort(e+1,e+ecnt+1,cmp); 
	// 选取前 min(ecnt, m) 个最大的乘法因子作为最终选中的操作
	for (ll i=1;i<=min(ecnt,m);i++) {ans[++acnt].id=e[i].id; ans[acnt].t=e[i].t;}

	// 对选中的操作排序:先赋值,再加法,最后乘法(保证应用顺序正确)
	sort(ans+1,ans+acnt+1,cmp2);

	// 输出选中的操作数量及其编号(按正确顺序)
	cout <<acnt<<endl;
	for (ll i=1;i<=acnt;i++) cout <<ans[i].id<<" ";
	return 0;
}

无注释版

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+5;
struct node
{
	double x;
	ll t,id;
}e[N];
struct Node
{
	ll id,t;
}ans[N];
struct edge
{
	ll t,x,id;
};
vector<edge>c[N];
ll a[N],ecnt,Max[N],Pos[N],acnt;
bool cmp(node x,node y){return x.x>y.x;}
bool cmp1(edge x,edge y){return x.x>y.x;}
bool cmp2(Node x,Node y){if (x.t!=y.t){return x.t<y.t;} return x.id<y.id;}
signed main()
{	
	std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
	ll k,n,m; cin >>k>>n>>m;
	for (ll i=1;i<=k;i++) cin >>a[i];
	for (ll _=1;_<=n;_++)
	{
		ll t,i,b; cin >>t>>i>>b;
		if (t==1) 
		{
			if (b>Max[i]) Max[i]=b,Pos[i]=_;
		}
		if (t==2) {c[i].push_back({t,b,_});}
		if (t==3) {e[++ecnt].x=1.0*b; e[ecnt].t=t,e[ecnt].id=_;}
	}
	for (ll i=1;i<=k;i++)
	{
		if (Max[i] && Max[i]>a[i]) c[i].push_back({1,Max[i]-a[i],Pos[i]}); 
	}
	for (ll i=1;i<=k;i++)
	{
		sort(c[i].begin(),c[i].end(),cmp1);
		for (auto j:c[i])
		{
			int t=j.t,x=j.x,id=j.id;
			e[++ecnt].x=1.0*(x+a[i])/a[i]; e[ecnt].t=t,e[ecnt].id=id;
			a[i]+=x;
		}
	 } 
	sort(e+1,e+ecnt+1,cmp); 
	for (ll i=1;i<=min(ecnt,m);i++) {ans[++acnt].id=e[i].id; ans[acnt].t=e[i].t;}
	sort(ans+1,ans+acnt+1,cmp2);
	cout <<acnt<<endl;
	for (ll i=1;i<=acnt;i++) cout <<ans[i].id<<" ";
	return 0;
}

posted @ 2026-03-02 09:53  头像是美食  阅读(17)  评论(1)    收藏  举报