P8134 ICPC 2020 WF Opportunity Cost
题目背景
ICPC2020 WF G
题目描述
As with most types of products, buying a new phone can be difficult.
One of the main challenges is that there are a lot of different
aspects of the phone that you might care about, such as its price, its
performance, and how user-friendly the phone is.
Typically, there will be no single phone that is simultaneously the
best at all of these things: the cheapest phone, the most powerful
phone, and the most user-friendly phone will likely be different phones.
Thus when buying a phone, you are forced to make some sacrifices by
balancing the different aspects you care about against each other and
choosing the phone that achieves the best compromise (where "best"
of course depends on what your priorities happen to be). One way of
measuring this sacrifice is known as the opportunity cost ,
which (for the purposes of this problem) we define as follows.
Suppose that you have bought a phone with price x x x, performance y y y,
and user-friendliness z z z. For simplicity, we assume that these three
values are measured on a comparable numeric scale where higher is
better. If there are n n n available phones, and the values
( x i , y i , z i ) (x_i,y_i,z_i) (xi,yi,zi) represent the (price, performance, user-friendliness)
of the i th i^{\text{th}} ith phone, then the opportunity cost of your phone
is defined as
max 1 ≤ i ≤ n ( max ( x i − x , 0 ) + max ( y i − y , 0 ) + max ( z i − z , 0 ) ) \max {1 \leq i \leq n}\left(\max \left(x{i}-x, 0\right)+\max \left(y_{i}-y, 0\right)+\max \left(z_{i}-z, 0\right)\right) 1≤i≤nmax(max(xi−x,0)+max(yi−y,0)+max(zi−z,0))
Write a program that, given the list of available phones, finds a
phone with the minimum opportunity cost.
输入格式
The first line of input contains an integer n n n ( 2 ≤ n ≤ 200 000 2 \leq n \leq 200\,000 2≤n≤200000), the number of phones considered. Following that are n n n lines.
The i th i^{\text{th}} ith of these lines contains three integers x i x_i xi, y i y_i yi, and z i z_i zi,
where x i x_i xi is the price, y i y_i yi is the performance, and z i z_i zi is the
user-friendliness of the i th i^{\text{th}} ith phone ( 1 ≤ x i , y i , z i ≤ 10 9 1 \leq x_i, y_i, z_i \leq 10^9 1≤xi,yi,zi≤109).
输出格式
Output a single line containing two integers: the smallest possible
opportunity cost and an integer between 1 1 1 and n n n indicating the
phone achieving that opportunity cost. If there are multiple such
phones, output the one with the smallest index.
输入输出样例 #1
输入 #1
4
20 5 5
5 20 5
5 5 20
10 10 10
输出 #1
10 4
输入输出样例 #2
输入 #2
4
15 15 5
5 15 15
15 5 15
10 10 10
输出 #2
10 1
枚举
cost(i)表示手机i的机会成本。
cost(i,j) = m a x ( x j − x i , 0 ) + m a x ( y j − y i , 0 ) + m a x ( z j − z − i , 0 ) max(x_j-x_i,0)+max(y_j-y_i,0)+max(z_j-z-i,0) max(xj−xi,0)+max(yj−yi,0)+max(zj−z−i,0)
cost(I,j,k1,k2,k3) = k 1 ∗ ( x j − x i ) + k 2 ∗ ( y j − y i ) + k 3 ∗ ( z j − z − i ) , k 1 , k 2 , k 3 ∈ 0 , 1 k1*(x_j-x_i)+k2*(y_j-y_i)+k3*(z_j-z-i),k1,k2,k3\in{0,1} k1∗(xj−xi)+k2∗(yj−yi)+k3∗(zj−z−i),k1,k2,k3∈0,1
性质一 : c o s t ( i ) = max j : 0 n − 1 c o s t ( i , j ) cost(i)=\max\limits_{j:0}^{n-1}cost(i,j) cost(i)=j:0maxn−1cost(i,j)
性质二 : c o s t ( i , j ) = max k 1 , k 2 , k 3 ∈ 0 , 1 c o s t ( i , j , k 1 , k 2 , k 3 ) cost(i,j)=\max\limits_{k1,k2,k3\in {0,1}} cost(i,j,k1,k2,k3) cost(i,j)=k1,k2,k3∈0,1maxcost(i,j,k1,k2,k3)
如果: x j > x i x_j > x_i xj>xi,cost(i,j,1,k2,k3) > cost(i,j,0,k2,k3)$ 两者相减 等于 ( x j − x i ) > 0 (x_j-x_i)>0 (xj−xi)>0即前者大于后者。
如果: x j < x i x_j < x_i xj<xi,cost(i,j,1,k2,k3) < cost(i,j,0,k2,k3)$ 两者相减 等于 ( x j − x i ) < 0 (x_j-x_i)<0 (xj−xi)<0即前者小于后者。
时间复杂度 :O(8nn)
f ( k 1 , k 2 , k 3 , j ) = k 1 × x j + k 2 × y j + k 3 × z j → c o s t ( i , j , k 1 , k 2 , k 3 ) = f ( k 1 , k 2 , k 3 , j ) − f ( k 1 , k 2 , k 3 , i ) f(k1,k2,k3,j) = k1\times x_j + k2 \times y_j + k3 \times z_j \rightarrow \\ cost(i,j,k1,k2,k3)=f(k1,k2,k3,j)-f(k1,k2,k3,i) f(k1,k2,k3,j)=k1×xj+k2×yj+k3×zj→cost(i,j,k1,k2,k3)=f(k1,k2,k3,j)−f(k1,k2,k3,i)
c o s t ( i , j ) = max k 1 , k 2 , k 3 ∈ 0 , 1 max j : 0 n − 1 ( f ( k 1 , k 2 , k 3 , j ) − f ( k 1 , k 2 , k 3 , i ) ) = max k 1 , k 2 , k 3 ∈ 0 , 1 ( max j : 0 n − 1 f ( k 1 , k 2 , k 3 , j ) − f ( k 1 , k 2 , k 3 , i ) ) cost(i,j)=\max\limits_{k1,k2,k3\in {0,1}}\max\limits_{j:0}^{n-1} (f(k1,k2,k3,j)-f(k1,k2,k3,i))\\ =\max\limits_{k1,k2,k3\in {0,1}}(\max\limits_{j:0}^{n-1}f(k1,k2,k3,j)-f(k1,k2,k3,i)) cost(i,j)=k1,k2,k3∈0,1maxj:0maxn−1(f(k1,k2,k3,j)−f(k1,k2,k3,i))=k1,k2,k3∈0,1max(j:0maxn−1f(k1,k2,k3,j)−f(k1,k2,k3,i))
我们预处理出: W ( k 1 , k 2 , k 3 ) = max j : 0 n − 1 f ( k 1 , k 2 , k 3 , j ) W(k1,k2,k3)=\max\limits_{j:0}^{n-1}f(k1,k2,k3,j) W(k1,k2,k3)=j:0maxn−1f(k1,k2,k3,j)
则上式 = max k 1 , k 2 , k 3 ∈ 0 , 1 W ( k 1 , k 2 , k 3 ) − f ( k 1 , k 2 , k 3 , j ) =\max\limits_{k1,k2,k3\in {0,1}}W(k1,k2,k3)-f(k1,k2,k3,j) =k1,k2,k3∈0,1maxW(k1,k2,k3)−f(k1,k2,k3,j)
时间复杂度:O(8n)
代码
核心代码
cpp
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>
#include <bitset>
using namespace std;
template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
in >> pr.first >> pr.second;
return in;
}
template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t);
return in;
}
template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
return in;
}
template<class T = int>
vector<T> Read() {
int n;
cin >> n;
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> ReadNotNum() {
vector<T> ret;
T tmp;
while (cin >> tmp) {
ret.emplace_back(tmp);
if ('\n' == cin.get()) { break; }
}
return ret;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<int N = 1'000'000>
class COutBuff
{
public:
COutBuff() {
m_p = puffer;
}
template<class T>
void write(T x) {
int num[28], sp = 0;
if (x < 0)
*m_p++ = '-', x = -x;
if (!x)
*m_p++ = 48;
while (x)
num[++sp] = x % 10, x /= 10;
while (sp)
*m_p++ = num[sp--] + 48;
AuotToFile();
}
void writestr(const char* sz) {
strcpy(m_p, sz);
m_p += strlen(sz);
AuotToFile();
}
inline void write(char ch)
{
*m_p++ = ch;
AuotToFile();
}
inline void ToFile() {
fwrite(puffer, 1, m_p - puffer, stdout);
m_p = puffer;
}
~COutBuff() {
ToFile();
}
private:
inline void AuotToFile() {
if (m_p - puffer > N - 100) {
ToFile();
}
}
char puffer[N], * m_p;
};
template<int N = 1'000'000>
class CInBuff
{
public:
inline CInBuff() {}
inline CInBuff<N>& operator>>(char& ch) {
FileToBuf();
ch = *S++;
return *this;
}
inline CInBuff<N>& operator>>(int& val) {
FileToBuf();
int x(0), f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
val = f ? -x : x; S++;//忽略空格换行
return *this;
}
inline CInBuff& operator>>(long long& val) {
FileToBuf();
long long x(0); int f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
val = f ? -x : x; S++;//忽略空格换行
return *this;
}
template<class T1, class T2>
inline CInBuff& operator>>(pair<T1, T2>& val) {
*this >> val.first >> val.second;
return *this;
}
template<class T1, class T2, class T3>
inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {
*this >> get<0>(val) >> get<1>(val) >> get<2>(val);
return *this;
}
template<class T1, class T2, class T3, class T4>
inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {
*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);
return *this;
}
template<class T = int>
inline CInBuff& operator>>(vector<T>& val) {
int n;
*this >> n;
val.resize(n);
for (int i = 0; i < n; i++) {
*this >> val[i];
}
return *this;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
*this >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> Read() {
vector<T> ret;
*this >> ret;
return ret;
}
private:
inline void FileToBuf() {
const int canRead = m_iWritePos - (S - buffer);
if (canRead >= 100) { return; }
if (m_bFinish) { return; }
for (int i = 0; i < canRead; i++)
{
buffer[i] = S[i];//memcpy出错
}
m_iWritePos = canRead;
buffer[m_iWritePos] = 0;
S = buffer;
int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);
if (readCnt <= 0) { m_bFinish = true; return; }
m_iWritePos += readCnt;
buffer[m_iWritePos] = 0;
S = buffer;
}
int m_iWritePos = 0; bool m_bFinish = false;
char buffer[N + 10], * S = buffer;
};
class Solution {
public:
pair<long long, int> Ans(vector<tuple<int, int, int>>& xyz) {
long long ans = LLONG_MAX / 2;
int inxAns = -1;
vector<long long> g[8];
long long llMax[8];
const int N = xyz.size();
for (int k1 = 0; k1 <= 1; k1++) {
for (int k2 = 0; k2 <= 1; k2++) {
for (int k3 = 0; k3 <= 1; k3++) {
const int inx = 4 * k1 + 2 * k2 + k3;
auto& f = g[inx]; f.resize(N);
for (int i = 0; i < N; i++) {
f[i] = (long long)k1 * get<0>(xyz[i]) + k2 * get<1>(xyz[i]) + k3 * get<2>(xyz[i]);
}
llMax[inx] = *max_element(f.begin(), f.end());
}
}
}
for (int i = 0; i < N; i++)
{
long long cur = LLONG_MIN / 2;
for (int inx = 0; inx < 8; inx++) {
cur = max(cur, llMax[inx] - g[inx][i]);
}
if (cur < ans) { ans = cur; inxAns = i; }
}
return { ans,inxAns };
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
ios::sync_with_stdio(0); cin.tie(nullptr);
CInBuff<> in; COutBuff<10'000'000> ob;
auto xyz = in.Read<tuple<int,int,int>>();
#ifdef _DEBUG
//printf("M=%d,a=%d,", M,a);
Out(xyz, "xyz=");
//Out(B, "B=");
//Out(que, "que=");
//Out(B, "B=");
#endif // DEBUG
auto res = Solution().Ans(xyz);
cout << res.first << " " << res.second + 1;
return 0;
}

扩展阅读
| 算法为骨,CAD为魂 |
|---|
| 亲士工具箱:支持中望CAD2024、AutoCad2013及以上,多年承接CAD项目的精华 |
| 工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
| 学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
| 活到老,学到老。明朝中后期,大约50%的进士能当上堂官(副部及更高);能当上堂官的举人只有十余人。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。
