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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
static vector<vector<int>> increments;
static vector<int> firstIncrement;
static long long K; // number of robots to build
static long long totalCount; // count of robots with extra cost <= threshold
static long long savings; // sum of (threshold - extra) over robots with extra <= threshold
// Count how many combinations (robots) have extra cost <= budget
static void countRobots(int idx, long long budget) {
if (totalCount >= K) return;
if (idx != -1 && budget < increments[idx][0]) {
// Skip blocks whose smallest increment is greater than budget
idx = int(upper_bound(firstIncrement.begin(), firstIncrement.begin() + idx, (int)budget) - firstIncrement.begin()) - 1;
}
if (idx == -1) {
// All remaining positions can stay at base (extra 0..budget)
totalCount++;
return;
}
countRobots(idx - 1, budget); // choose base at this position
const auto& inc = increments[idx];
for (int i = 0; i < (int)inc.size() && inc[i] <= budget; ++i) {
countRobots(idx - 1, budget - inc[i]); // choose one upgraded model here
if (totalCount >= K) return;
}
}
// Sum over all combinations with extra <= budget of (budget - extra)
static void accumulateSavings(int idx, long long budget) {
if (idx != -1 && budget < increments[idx][0]) {
idx = int(upper_bound(firstIncrement.begin(), firstIncrement.begin() + idx, (int)budget) - firstIncrement.begin()) - 1;
}
if (idx == -1) {
savings += budget + 1; // extras can be 0..budget, so contribute budget+1
return;
}
accumulateSavings(idx - 1, budget); // base choice
const auto& inc = increments[idx];
for (int i = 0; i < (int)inc.size() && inc[i] <= budget; ++i) {
accumulateSavings(idx - 1, budget - inc[i]); // upgraded choice
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
if (!(cin >> N >> K)) return 0;
long long baseCost = 0;
vector<vector<int>> blocks;
blocks.reserve(N);
long long hi = 0; // upper bound for extra cost
for (int i = 0; i < N; ++i) {
int m; cin >> m;
vector<int> v(m);
for (int j = 0; j < m; ++j) cin >> v[j];
sort(v.begin(), v.end());
baseCost += v[0];
if (m >= 2) {
vector<int> diffs;
diffs.reserve(m - 1);
for (int j = 1; j < m; ++j) diffs.push_back(v[j] - v[0]);
hi += diffs.back();
blocks.push_back(move(diffs));
}
}
int usefulN = (int)blocks.size();
if (usefulN == 0) {
// Every position had exactly one model; only one robot exists
cout << baseCost * K << '\n';
return 0;
}
// Sort positions by their smallest increment to enable pruning
sort(blocks.begin(), blocks.end(),
[](const vector<int>& a, const vector<int>& b) { return a.front() < b.front(); });
increments = move(blocks);
firstIncrement.resize(usefulN);
for (int i = 0; i < usefulN; ++i) firstIncrement[i] = increments[i][0];
// Binary search the minimal threshold 'lo' s.t. at least K robots have extra <= lo
long long lo = 0;
while (lo < hi) {
long long mid = (lo + hi) / 2;
totalCount = 0;
countRobots(usefulN - 1, mid);
if (totalCount < K) lo = mid + 1;
else hi = mid;
}
// Sum of K smallest extras = lo * K - sum_{extra <= lo-1}(lo - extra)
savings = 0;
if (lo > 0) accumulateSavings(usefulN - 1, lo - 1);
long long answer = (baseCost + lo) * K - savings;
cout << answer << '\n';
return 0;
}
|