Cheap Dinner

Cheap Dinner

Created by LXC on Wed Feb 28 15:05:43 2024

https://codeforces.com/problemset/problem/1487/E

ranting: 2000

tag: brute force, data structures, graphs, greedy, implementation, sortings, two pointers

problem

题目描述

4 种菜类——开胃菜,主菜,饮品和甜点。一顿晚饭由 4 种菜类各一道组成。

对于第 i 种菜类,共有 ni 种供选择。开胃菜、主菜、饮品和甜点价格分别为 aibicidi

有些菜品不能搭配。对于开胃菜和主菜来说,有 m1 对不能搭配。对于主菜和饮品、饮品和甜点分别有 m2m3 对。

试问总价格最小的晚饭需要多少钱?

输入

第一行有 n1n2n3n4

接下来四行分别为 aibicidi

接下来一行为 m1,接下来 m1 行中,每一行有 xiyi,表示第 xi 道开胃菜和第 yi 道主菜不能搭配。

主菜和饮品,饮品和甜点的搭配需求也以相同的方式输入。

输出

如果不存在,输出 -1

否则,输出最小花费。

数据规模

1ni1500000mi2000001ai,bi,ci,di108

保证 1xint1yint+1,且对于相同的 t(xi,yi) 互不相同。

solution

fi,j为已经选了i道菜,且第i道菜选择第j种菜的最大值。

初始化f1,i=ai

答案就是minf4,i

转移fi,j=ai,j+min<k,j> is availablefi1,k

例如我们可以记录每种第二道菜i有多少条指向第一道菜的边ei,由于ei=m1,我们可以先用平衡树存储所有的第一道菜种类,然后对于第二道菜的种类i,直接在平衡树种删除ei道菜,花费时间O(eilogn1),然后查询平衡树中最小值作为f2,i的转移来源。最后将删除的ei道菜重新加入平衡树,求出所有f2,?的复杂度为O(m1logn1)

总复杂度O(milogni)

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

#include <bits/stdc++.h>
#define SINGLE_INPUT
#define ll long long
#define ull unsigned long long
#define N 500005
#define MOD 998244353
using namespace std;

template<class t,class u> ostream& operator<<(ostream& os,const pair<t,u>& p) {
return os<<'['<<p.first<<", "<<p.second<<']';
}
template<class t> ostream& operator<<(ostream& os,const vector<t>& v) {
os<<'['; int s = 1;
for(auto e:v) { if (s) s = 0; else os << ", "; os << e; }
return os<<']';
}
template<class t,class u> ostream& operator<<(ostream& os,const map<t,u>& mp){
os<<'{'; int s = 1;
for(auto [x,y]:mp) { if (s) s = 0; else os << ", "; os<<x<<": "<<y; }
return os<<'}';
}
template<class t> ostream& operator<<(ostream& os,const multiset<t>& v) {
os<<'['; int s = 1;
for(auto e:v) { if (s) s = 0; else os << ", "; os << e; }
return os<<']';
}


void sol() {
int n[4];
for (int i=0; i<4; i++) cin >> n[i];
vector<vector<ll>> a(4), dp(4);
for (int i=0; i<4; i++) {
dp[i].resize(n[i], -1);
for (int j=0; j<n[i]; j++) {
int x;
cin >> x;
a[i].push_back(x);
}
}
vector<vector<vector<int>>> g(3);
for (int i=0; i<3; i++) {
int t;
cin >> t;
g[i].resize(n[i+1]);
while (t--) {
int x, y;
cin >> x >> y;
x--; y--;
g[i][y].push_back(x);
}
}
dp[0] = a[0];
for (int i=1; i<=3; i++) {
multiset<ll> st(dp[i-1].begin(), dp[i-1].end());
for (int j=0; j<n[i]; j++) {
for (int k:g[i-1][j]) {
st.erase(st.find(dp[i-1][k]));
}
if (st.size())
dp[i][j] = *st.begin()+a[i][j];
else
dp[i][j] = MOD;
for (int k:g[i-1][j]) {
st.insert(dp[i-1][k]);
}
}
// cout << dp[i] << endl;
}
// cout << dp << endl;
int ans = *min_element(dp[3].begin(), dp[3].end());
cout << (ans>=MOD?-1:ans) << "\n";
}

int main() {
cout << setprecision(15) << fixed;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifndef SINGLE_INPUT
int t;
cin >> t;
while (t--) {
sol();
}
#else
sol();
#endif
return 0;
}