NOIP2015推销员

Posted 走走

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2015推销员相关的知识,希望对你有一定的参考价值。

NOIP2015推销员

两种做法 : 第一种直接贪心, 第二种线段树.

参考 : https://ac.nowcoder.com/acm/problem/blogs/16493

贪心 :

第 k - 1 次选到的点, 第 k 次一定会选到, 答案是单调递增的. 每多一个点, 就去枚举疲劳值 j.

\\(b[j]:疲劳值为j的个数\\).

\\(pos[j][b[j]]:第b[j]个疲劳值为j的人家的位置.\\)

\\(last:已经选择的点中离原点最远的距离\\).

如果目前在枚举的位置 \\(pos[i][b[j]]>last\\), 如果选择它, 多增加的疲劳值应为 \\((pos[j][b[j]]-last)*2+j\\). 去枚举得到最大的疲劳值增量 \\(maxn=max(maxn,(pos[j][b[j]]-last)*2+j)\\).

如果目前在枚举的位置 \\(pos[i][b[j]]<last\\), 如果选择它, 多增加的疲劳值应为 \\(j\\) , 同样去枚举得到最大的疲劳值增量 \\(maxn=max(maxn,j)\\).

#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define ull unsigned long long
#define pb push_back
#define PII pair<int, int>
#define VIT vector<int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 1e5 + 10, M = 1010;
int a[N], v[N], b[M], pos[M][M], last;
ll sum;
int n;
 
int main() {
    //freopen("in.txt", "r", stdin);
    IO;
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) {
        cin >> v[i];
        int j = v[i];
        b[j]++;
        pos[j][b[j]] = a[i];
    }
    for (int i = 1; i <= n; ++i) {
        int maxn = 0, x = 0, y = 0;
        for (int j = 0; j < 1000; ++j) {
            if (b[j] <= 0) continue;
            if (pos[j][b[j]] > last && (pos[j][b[j]] - last) * 2 + j > maxn) {
                maxn = (pos[j][b[j]] - last) * 2 + j;
                x = j;
                y = pos[j][b[j]];
            }
            else if (pos[j][b[j]] <= last && j > maxn) {
                maxn = j;
                x = j;
                y = last;
            }
        }
        b[x]--;
        last = y;
        sum += maxn;
        cout << sum << \'\\n\';
    }
    return 0;
}

线段树 :

树中结点维护区间中选择哪户人家能得到最大疲劳值增量.

那么每多选择一户人家, 就要修改树中结点的值.

\\(now:已选择的点中最大距离.\\)

\\(id:当前得到最大疲劳值增量的下标.\\)

距离是递增的, 所以从头到尾只用枚举一遍. \\(now_i : 1 : n.\\)

\\(a[id]>a[now_i]\\) 时, now_i 的重复距离就可以去掉 : \\(modify(u, now_i,now_i,-a[now_i]*2)\\).

id + 1 到 n 之间的重复距离也要去掉 : \\(modify(u,id + 1, n, -(a[id]-now)*2)\\).

选择了 id, 它的疲劳值也要去掉 : \\(modify(u, id, id, -b[id])\\).

#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define ull unsigned long long
#define pb push_back
#define PII pair<int, int>
#define VIT vector<int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 1e5 + 10; 
int a[N], b[N];
int n;

struct Node {
    int l, r, add, m_id;
    ll maxn;
} tr[N * 4];
 
void pushup(Node &t, Node &l, Node &r) {
    if (l.maxn >= r.maxn) t.maxn = l.maxn, t.m_id = l.m_id;
    else t.maxn = r.maxn, t.m_id = r.m_id;
}

void pushup(int u) {
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void pushdown(Node &t, Node &l, Node &r) {
    l.add += t.add, r.add += t.add;
    l.maxn += t.add, r.maxn += t.add;
    t.add = 0;
}

void pushdown(int u) {
    pushdown(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r) {
    if (l == r) tr[u] = {l, l, 0, l, a[l] * 2 + b[l]};
    else {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void modify(int u, int l, int r, int d) {
    if (l > r) return;
    if (tr[u].l >= l && tr[u].r <= r) {
        tr[u].add += d;
        tr[u].maxn += d;
    } else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, d);
        if (r > mid) modify(u << 1 | 1, l, r, d);
        pushup(u);
    }
}

Node query(int u, int l, int r) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u];
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l > mid) return query(u << 1 | 1, l, r);
    else if (r <= mid) return query(u << 1, l, r);
    else {
        Node left = query(u << 1, l, r);
        Node right = query(u << 1 | 1, l, r);
        Node res;
        pushup(res, left, right);
        return res;
    }
}


int main() {
    IO;
    //freopen("D:\\\\Vim\\\\ACM\\\\B\\\\in.txt", "r", stdin); 
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) cin >> b[i];
    build(1, 1, n);
    int now = 0, now_i = 1;
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        Node t = query(1, 1, n);
        //cout << t.maxn << \' \' << t.m_id << \'\\n\';
        ans += t.maxn;
        cout << ans << \'\\n\';
        int id = t.m_id;
        if (a[id] > now) {
            for (; now_i <= n; now_i++) {
                if (a[id] >= a[now_i]) modify(1, now_i, now_i, -a[now_i] * 2);
                else break;
            }
            modify(1, now_i, n, -(a[id] - now) * 2);
            now = a[id];
        }
        modify(1, id, id, -b[id]);
        //cout << id << \' \' << now << \'\\n\';
    }
    return 0;
}

以上是关于NOIP2015推销员的主要内容,如果未能解决你的问题,请参考以下文章

noip2015普及组 推销员

推销员(NOIP2015 普及组第四题)

NOIP201504推销员

推销员(优先队列+贪心)

2015推销员

使SVG linearGradient遵循路径