NOIP2015推销员
Posted 走走
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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推销员的主要内容,如果未能解决你的问题,请参考以下文章