Loading

【题解】CF521D Shop

给定一个大小为 \(n\) 的序列和 \(m\) 个操作,每个操作是赋值 \(a_i = x\)\(a_i = a_i + x\)\(a_i = a_i \times x\),现在选出 \(k\) 个操作按任意顺序进行,使得最后 \(\prod a_i\) 最大。

首先由于赋值操作可以覆盖前面的操作,所以每个位置的赋值操作最多进行一次,且一定是这个位置的第一次操作。

由于 \(k(a_i + x) > ka_i + x\),所以乘法操作一定在最后进行。并且由于我们求的是 \(\prod a_i\),所以乘法操作可以看成直接对答案进行操作,我们只用排序后选最大的几个就行。

考虑加法操作,想办法让它变成和乘法操作一样。我们肯定按 \(x\) 从大到小排,优先选择大的。那么一次加法操作等价于乘法操作 \(\times \dfrac{s + x}{s}\),如果两个加法操作 \(x\ge y\),那么对应的两个乘法操作 \(\dfrac{s + x}{s} \ge \dfrac{s + x + y}{s + x}\),所以直接变成乘法操作,顺序不会改变,正确性可以保证。

最后还有赋值操作,由于赋值操作只有一次,可以直接把它看成一次 \(x- a_i\) 的加法即可。时间复杂度 \(\mathcal{O}((n + m + k)\log)\)

#define N 100005
int n, m, k, a[N], b[N], p[N], o[N];
vector<Pr>u[N];
struct node{
	int x, y;		// x / y;
	bool operator<(const node o)const{return x * (__int128)o.y > o.x * (__int128)y;}
};
vector<pair<node, int> >c;
vector<int>ed;
signed main() {
	read(n, m, k);
	rp(i, n)read(a[i]);
	rp(i, m){
		int op, x, y;
		read(op, x, y);
		o[i] = op;
		if(1 == op){
			if(y > b[x])b[x] = y, p[x] = i;
		}
		else if(2 == op)u[x].pb(mp(y, i));
		else c.pb(mp(node{y, 1}, i));
	}
	rp(i, n){
		if(b[i] > a[i])u[i].pb(mp(b[i] - a[i], p[i]));
		if(!u[i].empty()){
			sort(u[i].begin(), u[i].end());
			reverse(u[i].begin(), u[i].end());
			int s = a[i];
			go(x, u[i])c.pb(mp(node{s + x.fi, s}, x.se)), s += x.fi;
		}
	}
	sort(c.begin(), c.end());
	k = min(k, si(c));
	rep(i, 0, k - 1)ed.pb(c[i].se);
	sort(ed.begin(), ed.end(), [](int x,int y){return o[x] < o[y];});
	printf("%lld\n", k);
	go(x, ed)printf("%lld ", x);
	return 0;
}
posted @ 2022-05-13 20:03  7KByte  阅读(95)  评论(0编辑  收藏  举报