# | Time | Username | Problem | Language | Result | Execution time | Memory |
---|---|---|---|---|---|---|---|
869474 | loggerr | Permutation Recovery (info1cup17_permutation) | C++98 | 0 ms | 0 KiB |
This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <random>
#include <ctime>
#include <chrono>
const int length = 6;
const int base = 1e6; // основание системы счисления 10 ^ length
using std::vector;
class BigInteger {
private:
bool negative;
vector<int> number;
void remove_leading_zero() {
while (number.size() > 1 && number.back() == 0) {
number.pop_back();
}
if (number.size() == 1 && number[0] == 0) {
negative = false;
}
}
bool modular_comparison(const BigInteger &other) { // true if abs(me) <= abs(other)
if (number.size() < other.number.size()) {
return true;
} else if (number.size() > other.number.size()) {
return false;
}
for (int idx = static_cast<int>(number.size()) - 1; idx >= 0; --idx) {
if (number[idx] > other.number[idx]) {
return false;
}
if (number[idx] < other.number[idx])
return true;
}
return true;
}
BigInteger multiply(int digit, size_t start = 0) const {
BigInteger result = *this;
int carry = 0;
for (size_t idx = start; idx < result.number.size() || carry != 0; ++idx) {
if (result.number.size() == idx)
result.number.push_back(0);
long long res = static_cast<long long>(result.number[idx]) * digit + carry;
carry = static_cast<int>(res / base);
res -= carry * 1LL * base;
result.number[idx] = static_cast<int>(res);
}
result.remove_leading_zero();
return result;
}
void shift_left(size_t need = 1) {
if (need <= 5) {
for (size_t idx = 0; idx < need; ++idx)
number.insert(number.begin(), 0);
} else {
std::reverse(number.begin(), number.end());
number.resize(number.size() + need);
std::reverse(number.begin(), number.end());
}
}
void shift_right() {
number.erase(number.begin());
}
public:
BigInteger() : negative(false) {
number.resize(1, 0);
}
BigInteger(const BigInteger &other) :
negative(other.negative), number(other.number) {}
BigInteger(int num) : negative(false) {
if (num < 0)
negative = true, num = -num;
if (num == 0) {
*this = BigInteger();
} else {
while (num > 0) {
number.push_back(num % base);
num /= base;
}
}
}
explicit BigInteger(unsigned long long num) : negative(false) {
if (num == 0) {
*this = BigInteger();
} else {
while (num > 0) {
number.push_back(static_cast<int>(num % base));
num /= base;
}
}
}
BigInteger(const char* other, size_t len) {
negative = other[0] == '-';
int st = (negative ? 1 : 0);
for (int idx = static_cast<int>(len) - 1; idx >= st; idx -= length) {
int left = std::max(st, idx - length + 1);
int right = idx;
number.push_back(0);
for (int i = left; i <= right; ++i) {
number.back() *= 10;
number.back() += other[i] - '0';
}
}
remove_leading_zero();
}
BigInteger(const std::string &other) :
BigInteger(other.c_str(), other.size()) {}
void swap(BigInteger &other) {
std::swap(number, other.number);
std::swap(negative, other.negative);
}
BigInteger& operator=(BigInteger other) {
swap(other);
return *this;
}
BigInteger operator-() const {
BigInteger copy(*this);
copy.negative = !copy.negative;
copy.remove_leading_zero();
return copy;
}
BigInteger& operator+=(BigInteger other) {
if (negative == other.negative) {
int carry = 0;
for (size_t idx = 0; idx < other.number.size() || carry != 0; ++idx) {
if (number.size() == idx)
number.push_back(0);
number[idx] += carry + (idx < other.number.size() ? other.number[idx] : 0);
carry = 0;
if (number[idx] >= base)
number[idx] -= base, carry = 1;
}
} else {
if (modular_comparison(other)) {
negative = other.negative;
int carry = 0;
for (size_t idx = 0; idx < other.number.size(); ++idx) {
if (number.size() == idx)
number.push_back(0);
int digit = number[idx];
number[idx] = other.number[idx] - (digit + carry);
carry = 0;
if (number[idx] < 0)
number[idx] += base, carry = 1;
}
} else {
int carry = 0;
for (size_t idx = 0; idx < other.number.size() || carry != 0; ++idx) {
number[idx] -= carry + (idx < other.number.size() ? other.number[idx] : 0);
carry = 0;
if (number[idx] < 0)
number[idx] += base, carry = 1;
}
}
}
remove_leading_zero();
return *this;
}
BigInteger& operator-=(const BigInteger &other) {
return *this += -other;
}
BigInteger& operator*=(const BigInteger &other) {
negative = negative ^ other.negative;
vector<long long> poly(number.size() + other.number.size());
for (size_t i = 0; i < number.size(); ++i) {
for (size_t j = 0; j < other.number.size(); ++j) {
poly[i + j] += number[i] * 1LL * other.number[j];
}
}
long long carry = 0;
for (size_t idx = 0; idx < poly.size() || carry != 0; ++idx) {
if (poly.size() == idx)
poly.push_back(0);
if (number.size() == idx)
number.push_back(0);
poly[idx] += carry;
carry = poly[idx] / base;
poly[idx] -= base * 1LL * carry;
number[idx] = static_cast<int>(poly[idx]);
}
remove_leading_zero();
return *this;
}
BigInteger& operator/=(const BigInteger &other) {
if (number.size() < other.number.size()) {
return *this = BigInteger();
}
bool flag = negative ^ other.negative;
BigInteger me = other;
me.make_abs();
make_abs();
size_t need = number.size() - other.number.size() + 1;
me.shift_left(need - 1);
vector<int> digits(need);
for (int idx = static_cast<int>(digits.size()) - 1; idx >= 0; --idx) {
int lhs = 0, rhs = base;
while (rhs - lhs > 1) {
int mid = (lhs + rhs) / 2;
BigInteger divisor = me.multiply(mid, idx);
if (divisor.modular_comparison(*this)) {
lhs = mid;
} else {
rhs = mid;
}
}
*this -= me.multiply(lhs);
digits[idx] = lhs;
me.shift_right();
}
number = digits;
negative = flag;
remove_leading_zero();
return *this;
}
BigInteger& operator%=(const BigInteger &other) {
return *this = *this - (*this / other) * other;
}
BigInteger operator+(const BigInteger &other) const {
BigInteger copy(*this);
copy += other;
return copy;
}
BigInteger operator-(const BigInteger &other) const {
BigInteger copy(*this);
copy -= other;
return copy;
}
BigInteger operator*(const BigInteger &other) const {
BigInteger copy = *this;
copy *= other;
return copy;
}
BigInteger operator/(const BigInteger &other) const {
BigInteger copy = *this;
copy /= other;
return copy;
}
BigInteger operator%(const BigInteger &other) const {
BigInteger copy = *this;
copy %= other;
return copy;
}
BigInteger& operator++() {
return *this += 1;
}
BigInteger operator++(int) {
BigInteger copy = *this;
*this += 1;
return copy;
}
BigInteger& operator--() {
return *this -= 1;
}
BigInteger operator--(int) {
BigInteger copy = *this;
*this -= 1;
return copy;
}
std::string toString() const {
std::string result = (negative ? "-" : "");
for (int idx = static_cast<int>(number.size()) - 1; idx >= 0; --idx) {
std::string digit = std::to_string(number[idx]);
if (static_cast<size_t>(idx + 1) < number.size())
digit = std::string(length - digit.size(), '0') + digit;
result += digit;
}
return result;
}
explicit operator bool() const {
for (int digit : number) {
if (digit) return true;
}
return false;
}
std::weak_ordering operator<=>(const BigInteger &other) const {
if (negative != other.negative) {
return other.negative <=> negative;
}
if (!negative) {
if (number.size() != other.number.size()) {
return number.size() <=> other.number.size();
}
for (int idx = static_cast<int>(number.size()) - 1; idx >= 0; --idx) {
if (number[idx] != other.number[idx]) {
return number[idx] <=> other.number[idx];
}
}
return std::weak_ordering::equivalent;
} else {
if (number.size() != other.number.size()) {
return other.number.size() <=> number.size();
}
for (int idx = static_cast<int>(number.size()) - 1; idx >= 0; --idx) {
if (number[idx] != other.number[idx]) {
return other.number[idx] <=> number[idx];
}
}
return std::weak_ordering::equivalent;
}
}
bool operator==(const BigInteger &other) const {
if (negative == other.negative && number.size() == other.number.size()) {
return number == other.number;
}
return false;
}
bool operator!=(const BigInteger &other) const {
return !(*this == other);
}
void change_sign() {
negative = !negative;
remove_leading_zero();
}
void make_abs() {
negative = false;
}
bool sign() const {
return negative;
}
void pow(size_t cnt) {
shift_left(cnt);
}
};
BigInteger operator""_bi(const char *other, size_t len) {
return BigInteger(other, len);
}
BigInteger operator""_bi(unsigned long long number) {
return BigInteger(number);
}
std::istream& operator>>(std::istream& is, BigInteger& me) {
is.tie(nullptr);
std::string number;
is >> number;
me = BigInteger(number);
return is;
}
std::ostream& operator<<(std::ostream& os, const BigInteger& me) {
os << me.toString();
return os;
}
BigInteger operator+(int number, const BigInteger &other) {
return BigInteger(number) + other;
}
BigInteger operator-(int number, const BigInteger &other) {
return BigInteger(number) - other;
}
BigInteger operator*(int number, const BigInteger &other) {
return BigInteger(number) * other;
}
BigInteger operator/(int number, const BigInteger &other) {
return BigInteger(number) / other;
}
BigInteger operator%(int number, const BigInteger &other) {
return BigInteger(number) % other;
}
BigInteger operator+(unsigned long long number, const BigInteger &other) {
return BigInteger(number) + other;
}
BigInteger operator-(unsigned long long number, const BigInteger &other) {
return BigInteger(number) - other;
}
BigInteger operator*(unsigned long long number, const BigInteger &other) {
return BigInteger(number) * other;
}
BigInteger operator/(unsigned long long number, const BigInteger &other) {
return BigInteger(number) / other;
}
BigInteger operator%(unsigned long long number, const BigInteger &other) {
return BigInteger(number) % other;
}
BigInteger gcd(BigInteger left, BigInteger right) {
left.make_abs(), right.make_abs();
while (right != BigInteger(0)) {
left %= right;
left.swap(right);
}
return left;
}
class Rational {
private:
BigInteger numerator, denominator;
void normalize_sign() { // invariant denominator >= 0
if (denominator.sign()) {
denominator.change_sign();
numerator.change_sign();
}
}
void normalize() {
BigInteger g = gcd(numerator, denominator);
if (g != BigInteger(0)) {
numerator /= g, denominator /= g;
}
}
public:
Rational() : numerator(0), denominator(1) {}
Rational(const Rational &other) : numerator(other.numerator), denominator(other.denominator) {}
Rational(const BigInteger &number) : numerator(number), denominator(1) {}
Rational(const BigInteger &number, const BigInteger &other) :
numerator(number), denominator(other) {
normalize_sign();
}
Rational(int number) : numerator(number), denominator(1) {}
void swap(Rational &other) {
numerator.swap(other.numerator);
denominator.swap(other.denominator);
}
Rational& operator=(Rational other) {
swap(other);
return *this;
}
Rational operator-() const {
Rational copy(-numerator, denominator);
return copy;
}
Rational& operator+=(const Rational &other) {
numerator = (numerator * other.denominator + other.numerator * denominator);
denominator = (denominator * other.denominator);
normalize_sign();
normalize();
return *this;
}
Rational& operator-=(const Rational &other) {
numerator = (numerator * other.denominator - other.numerator * denominator);
denominator = (denominator * other.denominator);
normalize_sign();
normalize();
return *this;
}
Rational& operator*=(const Rational &other) {
numerator *= other.numerator;
denominator *= other.denominator;
normalize_sign();
normalize();
return *this;
}
Rational& operator/=(const Rational &other) {
numerator *= other.denominator;
denominator *= other.numerator;
normalize_sign();
normalize();
return *this;
}
Rational operator+(const Rational &other) const {
Rational copy = *this;
copy += other;
return copy;
}
Rational operator-(const Rational &other) const {
Rational copy = *this;
copy -= other;
return copy;
}
Rational operator*(const Rational &other) const {
Rational copy = *this;
copy *= other;
return copy;
}
Rational operator/(const Rational &other) const {
Rational copy = *this;
copy /= other;
return copy;
}
bool sign() const {
return numerator.sign();
}
std::weak_ordering operator<=>(const Rational &other) const {
return (numerator * other.denominator - other.numerator * denominator) <=> BigInteger(0);
}
bool operator==(const Rational &other) const {
return numerator == other.numerator && denominator == other.denominator;
}
bool operator!=(const Rational &other) const {
return !(*this == other);
}
std::string toString() const {
std::string result;
result += numerator.toString();
if (denominator != BigInteger(1)) {
result += "/" + denominator.toString();
}
return result;
}
std::string asDecimal(size_t precision = 0) const {
if (numerator == BigInteger(0)) {
std::string res = "0";
if (precision) res += '.';
res += std::string(precision, '0');
return res;
}
if (precision == 0) {
return (numerator / denominator).toString();
}
bool sgn = sign();
BigInteger left = numerator;
BigInteger right = denominator;
left.make_abs();
right.make_abs();
std::string result;
if (sgn) result = "-";
result += (left / right).toString();
left %= right;
size_t extra = (precision + length - 1) / length;
left.pow(extra);
std::string fraction = (left / right).toString();
fraction = std::string(extra * length - fraction.size(), '0') + fraction;
fraction.resize(precision);
result += "." + fraction;
return result;
}
explicit operator double() const {
std::string str = asDecimal(5);
double result = std::stod(str);
return result;
}
};
Rational operator+(int number, const Rational &other) {
return Rational(number) + other;
}
Rational operator-(int number, const Rational &other) {
return Rational(number) - other;
}
Rational operator*(int number, const Rational &other) {
return Rational(number) * other;
}
Rational operator/(int number, const Rational &other) {
return Rational(number) / other;
}
using namespace std;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
const int Mod = 1e9 + 7;
struct node {
node *l, *r;
long long y;
int id, c;
BigInteger val, sm;
node (int _id, const BigInteger &_val) {
y = rnd() % Mod;
l = r = nullptr;
c = 1;
id = _id, val = _val, sm = _val;
}
};
int get_c(node *x) {
if (x == nullptr) return 0;
return x->c;
}
BigInteger get_sm(node *x) {
if (x == nullptr) return 0;
return x->sm;
}
void upd(node * x) {
if (x == nullptr) return;
x->c = 1 + get_c(x->l) + get_c(x->r);
x->sm = x->val + get_sm(x->l) + get_sm(x->r);
}
int get_x(node *x) {
return get_c(x->l);
}
pair<node *, node *> split(node *t, int key) {
if (!t) return {nullptr, nullptr};
if (get_x(t) <= key) {
pair<node *, node *> res = split(t->r, key - get_x(t) - 1);
t->r = res.first;
upd(t);
return {t, res.second};
} else {
pair<node *, node *> res = split(t->l, key);
t->l = res.second;
upd(t);
return {res.first, t};
}
}
node *merge(node *tl, node *tr) {
if (!tl) return tr;
if (!tr) return tl;
if (tl->y >= tr->y) {
tl->r = merge(tl->r, tr);
upd(tl);
return tl;
} else {
tr->l = merge(tl, tr->l);
upd(tr);
return tr;
}
}
int find_order(node *t, BigInteger value, int &pos) {
if (t == nullptr) return pos;
if (get_sm(t->l) + t->val < value) {
pos += get_c(t->l) + 1;
value -= get_sm(t->l) + t->val;
return find_order(t->r, value, pos);
} else {
return find_order(t->l, value, pos);
}
}
vector<int> p;
int last;
void order(node *t) {
if (t == nullptr) return;
order(t->l);
p[t->id] = last++;
order(t->r);
}
inline void solve() {
int n;
cin >> n;
vector<BigInteger> pref(n);
for (int i = 0; i < n; ++i) {
cin >> pref[i];
}
vector<BigInteger> dp(n);
dp[0] = pref[0];
for (int i = 1; i < n; ++i) {
dp[i] = pref[i] - pref[i - 1];
}
node *root = new node(0, dp[0]);
for (int i = 1; i < n; ++i) {
int pf = 0;
int pos = find_order(root, dp[i], pf);
node *next = new node(i, dp[i]);
auto [l, r] = split(root, pos - 1);
root = merge(l, merge(next, r));
}
last = 0;
p.resize(n);
order(root);
for (int i = 0; i < n; ++i) {
cout << p[i] + 1 << ' ';
}
cout << '\n';
}