zoukankan      html  css  js  c++  java
  • CF521D Shop

    Description

    洛谷传送门

    Solution

    一道非常友好毒瘤的贪心题。

    前置:本文与题目中变量名不同,本文:有 (n) 个正整数,(m) 个操作,选 (k) 个。

    题目中要求 3 种操作。

    • (a_i) 赋值为 (b);

    • (a_i) 加上 (b);

    • (a_i) 乘上 (b)

    一个显然的贪心,一定是先赋值,再加法,最后乘法。

    我们可以从简化版开始考虑。

    如果全部都是乘法,那么我们把 (b) 按从大到小排序,取前 (k) 个即可。

    但是还有赋值操作和加法操作,那该怎么办呢?

    很简单。

    假设把 (a) 赋值为 (b),那就相当于 (a = a * frac{b}{a})

    (a) 加上 (b),就相当于 (a = a * frac{a + b}{a})

    好!这题切了,写代码!交!

    ……

    那这是怎么回事呢?小编也觉得很奇怪。

    这大概是因为,我们在做加法时,每次都是对原数进行改动,当存在多个数时,贪心的正确性就无法保证了。

    所以加法操作要存下来,从大到小进行排序,然后做个前缀和,再改成乘法形式。

    对于赋值操作,我们只记录最大的一次赋值即可,注意要先改成加法,再改成乘法,因为这个最大的赋值也可能不选。

    这道题写数组,(vector),或优先队列都可以,我这里用的优先队列(调了好久 (QwQ))。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #define ll long long
    
    using namespace std;
    
    const ll N = 1e5 + 10;
    ll n, m, k;
    struct node{
    	ll id, x, type;
    	double val;
    	bool operator < (const node &b) const{
    		return val < b.val;
    	}
    };
    struct Ans{
    	ll type, pos;
    	bool operator < (const Ans &b) const{
    		return type != b.type ? type < b.type : pos < b.pos;
    	}
    }ans[N];
    priority_queue <node> q, q2, q3[N];//q:乘法  q2:赋值  q3:加法
    double a[N], b[N];
    ll cnt;
    bool vis[N];//vis[i]:记录第 i 个数的最大赋值操作是否计算过。
    
    signed main(){
    	scanf("%lld%lld%lld", &n, &m, &k);
    	for(ll i = 1; i <= n; i++)
    		scanf("%lf", &a[i]), b[i] = a[i];
    	for(ll i = 1; i <= m; i++){
    		ll op, x;
    		double y;
    		scanf("%lld%lld%lf", &op, &x, &y);
    		if(op == 1 && y > a[x]) q2.push((node){i, x, 1, y});
    		if(op == 2) q3[x].push((node){i, x, 2, y});
    		if(op == 3) q.push((node){i, x, 3, y});
    	}
    	while(!q2.empty()){//赋值操作改成加法。
    		node now = q2.top();
    		q2.pop();
    		if(!vis[now.x]) vis[now.x] = 1, now.val -= a[now.x], q3[now.x].push(now);//赋值操作改成加法的话,就是 a = b - a
    	}
    	ll sum = 0;
    	for(int i = 1; i <= n; i++){//加法改成乘法
    		sum = a[i];
    		while(!q3[i].empty()){
    			node now = q3[i].top();
    			q3[i].pop();
    			ll tmp = now.val;//注意先转存一下,不然值就变了,不转存的话也是在第 149 个点Wa。
    			now.val = (now.val + sum) / sum;
    			sum += tmp;
    			q.push(now);
    		}
    	}
    	for(ll i = 1; i <= k && !q.empty(); i++){//取前 k 个。
    		node now = q.top(); 
    		q.pop();
    		ans[++cnt] = (Ans){now.type, now.id};
    	}
    	sort(ans + 1, ans + 1 + cnt);//题目要求按操作种类从小到大排序,即先赋值,在加法,再乘法
    	printf("%lld
    ", cnt);
    	for(ll i = 1; i <= cnt; i++)
    		printf("%lld ", ans[i].pos);
    	puts("");
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15378632.html

  • 相关阅读:
    对生产稳定的一些思考
    tsar指标解释
    tsar采集nginx指标
    Nginx如何处理一个连接
    Java : 如何更优雅的设计异常
    MySql的索引实现
    IntelliJ Idea 常用配置
    ICSharpCode.SharpZipLib.dll 压缩、解压Zip文件 附源码
    Java BigDecimal使用
    社交系统中用户好友关系数据库设计
  • 原文地址:https://www.cnblogs.com/xixike/p/15378632.html
Copyright © 2011-2022 走看看