前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >洛谷2672(数据处理技巧)

洛谷2672(数据处理技巧)

作者头像
ACM算法日常
发布2019-03-19 16:39:16
4940
发布2019-03-19 16:39:16
举报
文章被收录于专栏:ACM算法日常

虽然这题的一般标签是贪心,不过此处笔者想强调的是题解中所运用的数据处理方式(各种前缀和的组合)。

题目描述:

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。

阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

输入格式:

第一行有一个正整数N,表示螺丝街住户的数量。

接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。

接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<1000。

输出格式:

输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。

题目本质:最优决策一定只在两种情况里选择:前X大的A值、前X-1大的A值加上一个S+2*A最大的。

解决方法:

首先按照A的从大到小排序。

维护:1.A的前缀和;2.前i个里最大的S;3.从i往后最大的S+2*A。

然后O(n)max一遍即可,代码注释里接着聊:

代码语言:javascript
复制
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <fstream>
#define ri readint()
#define gc getchar()
#define R(x) scanf("%d", &x)
#define W(x) printf("%d\n", x)
#define init(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define irep(i, a, b) for (int i = a; i >= b; i--)
#define ls p << 1
#define rs p << 1 | 1
using namespace std;

typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
const int inf = 0x3f3f3f3f;
const ll INF = 1e18;

/*****正文开始*****/

inline int readint() {//普通快读
    int x = 0, s = 1, c = gc;
    while (c <= 32) c = gc;
    if (c == '-')   s = -1, c = gc;
    for (; isdigit(c); c = gc)
        x = x * 10 + c - 48;
    return x * s;
}

const int maxn = 1e5 + 5;
struct family {
    int s, a;//s是距离,a是疲劳值

    family() {
    //初始值设为inf跟题意无关
    //只是笔者使用1~n的标号,这样从大到小排序时不用管下标为0了
    //其实不用搞这种麻烦事情的……
        s = a = inf;
    }

    bool operator < (const family b) const {
        return a > b.a;//按a值从大到小排
    }
};

int main() {
    int n = ri;//读入n
    vector<family> v(n + 1);//开数组
    //输入、按a排序
    rep(i, 1, n)    v[i].s = ri;
    rep(i, 1, n)    v[i].a = ri;
    sort(v.begin(), v.end());

    int maxpres[n+1];//前i个家庭中s值最大为多少
    int suma[n+1];//前i个家庭a值的前缀和
    int maxsufall[n+2];//从i往后(包括i)的家庭中最大的s+2*a为多少,维护这个东西跟题目性质有关
    init(maxpres, 0), init(suma, 0), init(maxsufall, 0);//初始化为0

    //计算各个要维护的值
    rep(i, 1, n)    maxpres[i] = max(maxpres[i - 1], v[i].s);
    rep(i, 1, n)    suma[i] = suma[i - 1] + v[i].a;
    irep(i, n, 1)   maxsufall[i] = max(maxsufall[i + 1], v[i].a + v[i].s * 2);

    vector<int> ans;//要么是直接取前i个,要么取i-1个加上后面取一个
    rep(i, 1, n)    ans.push_back(max(suma[i] + 2 * maxpres[i], suma[i - 1] + maxsufall[i]));
    for (int i : ans)   W(i);//输出
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ACM算法日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档