# | Time | Username | Problem | Language | Result | Execution time | Memory |
---|---|---|---|---|---|---|---|
1251418 | jwvg0425 | Souvenirs (IOI25_souvenirs) | C++20 | 0 ms | 0 KiB |
#include "souvenirs.h"
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <iostream>
#include <string>
#include <bitset>
#include <map>
#include <set>
#include <tuple>
#include <string.h>
#include <math.h>
#include <random>
#include <functional>
#include <assert.h>
#define all(x) (x).begin(), (x).end()
#define xx first
#define yy second
using namespace std;
template<typename T, typename Pr = less<T>>
using pq = priority_queue<T, vector<T>, Pr>;
using i64 = long long int;
using ii = pair<int, int>;
using ii64 = pair<i64, i64>;
// -1 이면 아직 안 밝혀진 값
int buyCount[105];
i64 values[105];
// (안 밝혀진 원소, 원소 전체 합)으로만 이루어진 쿼리
vector<pair<vector<int>, i64>> queries;
vector<int> firstCheck;
set<i64> used;
bool buyOk(int N)
{
for (int i = 0; i < N; i++)
{
if (buyCount[i] != i)
return false;
}
return true;
}
// v로 쿼리 - 확정 안 된 목록에서 x/k 재귀 반복, k=1일 때 확정짓고 종료
void query(int N, i64 v)
{
used.insert(v);
auto [ls, rem] = transaction(v);
i64 s = v - rem;
vector<int> rq;
for (auto& a : ls)
{
buyCount[a]++;
if (values[a] != -1)
s -= values[a];
else
rq.push_back(a);
}
if (rq.empty())
return;
if (rq.size() == 1)
{
values[rq[0]] = s;
if (rq[0] < N - 1)
firstCheck.push_back(rq[0] + 1);
return;
}
queries.emplace_back(rq, s);
i64 nq = s / rq.size();
query(N, nq);
}
void reduce(int N)
{
while (true)
{
bool hasUpdate = false;
for (auto& [q, s] : queries)
{
vector<int> nq;
i64 ns = s;
for (auto& qi : q)
{
if (values[qi] != -1)
ns -= values[qi];
else
nq.push_back(qi);
}
if (ns != s)
hasUpdate = true;
if (nq.size() == 1)
{
values[nq[0]] = ns;
if (nq[0] < N - 1)
firstCheck.push_back(nq[0] + 1);
}
q = nq;
s = ns;
}
vector<pair<vector<int>, i64>> nqueries;
for (auto& [q, s] : queries)
{
if (q.size() >= 2)
nqueries.emplace_back(q, s);
}
queries = nqueries;
if (!hasUpdate)
break;
}
}
void buy_souvenirs(int N, i64 P0) {
memset(values, -1, sizeof(values));
values[0] = P0;
firstCheck.push_back(1);
// 값 탐색
while (any_of(values, values + N, [](i64 v) { return v == -1; }))
{
// 값 확정 추가하는 쿼리 과정 수행
sort(all(firstCheck));
vector<int> nfirstCheck;
for (auto& f : firstCheck)
{
if (values[f] == -1)
nfirstCheck.push_back(f);
}
firstCheck = nfirstCheck;
if (!firstCheck.empty())
{
auto v = firstCheck.back();
firstCheck.pop_back();
query(N, values[v - 1] - 1);
}
else
{
sort(all(queries), [](auto& l, auto& r) { return l.xx.size() < r.xx.size(); });
for (auto& [q, s] : queries)
{
if (used.find(s) != used.end())
continue;
query(N, s / q.size());
break;
}
}
// 확정된 값을 기반으로 queries 갱신하는 작업 수행
reduce(N);
}
check();
// 구매 횟수 모자란 거 구매
while (!buyOk(N))
{
bool ok = false;
for (int i = 1; i < N; i++)
{
if (buyCount[i] == i)
continue;
for (int j = i + 1; j < N; j++)
{
if (buyCount[j] == j)
continue;
i64 p = values[i] + values[j];
if (p >= values[i - 1])
continue;
transaction(p);
buyCount[i] += 1;
buyCount[j] += 1;
ok = true;
break;
}
if (ok)
break;
}
if (!ok)
{
for (int i = 1; i < N; i++)
{
if (buyCount[i] == i)
continue;
buyCount[i] += 1;
transaction(values[i]);
break;
}
}
}
}