CF EDU 104 E - Cheap Dinner
E - Cheap Dinner
枚举
枚举第 2 种食物,求出每个第 2 种与第 1 种食物搭配的和的最小值,把这个最小值赋给第 2 种食物
枚举第 3 种食物,求出每个第 3 种与第 2 种食物搭配的和的最小值,把这个最小值赋给第 3 种食物
枚举第 4 种食物,求出每个第 4 种与第 3 种食物搭配的和的最小值,把这个最小值赋给第 4 种食物
答案就是最小的第 4 种食物的值
枚举的过程可先排序,比如枚举第 2 种食物的每个食物与第 1 种食物的每个食物的最小值时,如果第 1 种食物是排好序的,直接从小到大找到第一个没被 ban 掉的就可以,因为 ban 掉的搭配只有 O(m) 级别,所以枚举的次数也是 O(m) 的
注意要用结构体存下每个食物的编号,因为排序后编号就乱了,而 ban 掉的搭配是按原始编号的
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1.5e5 + 10;
const ll INF = 1e18;
int n1, n2, n3, n4;
struct Node
{
int id;
ll val;
bool operator<(const Node &x) const
{
return val < x.val;
}
}a1[N], a2[N], a3[N], a4[N];
void solve(Node a[], Node b[], int n, int m)
{
int q;
cin >> q;
set<PII> st;
while(q--)
{
int x, y;
cin >> x >> y;
st.insert({x, y});
}
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
for (int i = 1; i <= m; i++)
{
bool flag = false;
for (int j = 1; j <= n; j++)
{
if (!st.count({a[j].id, b[i].id}))
{
flag = true;
b[i].val += a[j].val;
break;
}
}
if (!flag)
b[i].val = INF;
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n1 >> n2 >> n3 >> n4;
for (int i = 1; i <= n1; i++)
cin >> a1[i].val, a1[i].id = i;
for (int i = 1; i <= n2; i++)
cin >> a2[i].val, a2[i].id = i;
for (int i = 1; i <= n3; i++)
cin >> a3[i].val, a3[i].id = i;
for (int i = 1; i <= n4; i++)
cin >> a4[i].val, a4[i].id = i;
solve(a1, a2, n1, n2);
solve(a2, a3, n2, n3);
solve(a3, a4, n3, n4);
ll ans = min_element(a4 + 1, a4 + n4 + 1)->val;
if (ans < INF / 2)
cout << ans << endl;
else
cout << -1 << endl;
return 0;
}