結果
| 問題 | No.3408 1215 Segments |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-12-01 22:01:16 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
AC
|
| 実行時間 | 743 ms / 2,500 ms |
| コード長 | 15,188 bytes |
| 記録 | |
| コンパイル時間 | 3,443 ms |
| コンパイル使用メモリ | 295,848 KB |
| 実行使用メモリ | 7,848 KB |
| 最終ジャッジ日時 | 2025-12-14 23:35:16 |
| 合計ジャッジ時間 | 41,629 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 46 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef std::pair<long long, long long> P;
typedef std::priority_queue<P, std::vector<P>, std::greater<P>> PQ;
typedef std::complex<double> cd;
struct P3 {
long long first, second, third;
};
struct P3P {
P first, second, third;
};
struct compP3{
bool operator()(const P3 &p1,const P3 &p2) const {
if (p1.first != p2.first) return p1.first < p2.first;
if (p1.second != p2.second) return p1.second < p2.second;
else return p1.third < p2.third;
}
};
struct gcompP3{
bool operator()(const P3 &p1,const P3 &p2) const {
if (p1.first != p2.first) return p1.first > p2.first;
if (p1.second != p2.second) return p1.second > p2.second;
else return p1.third > p2.third;
}
};
const double PI = acos(-1.0);
bool ckran(int a, int n) {
return (a >= 0 && a < n);
}
void yn (bool f) {
if (f) std::cout << "Yes" << '\n';
else std::cout << "No" << '\n';
}
long long pplus(P a) {
return a.first + a.second;
}
long long pminus(P a) {
return a.first - a.second;
}
long long ptime(P a) {
return a.first * a.second;
}
long long pdiv(P a) {
return a.first / a.second;
}
template<typename T, typename U>
bool chmax(T& a, U b) {
if (a < b) {
a = b;
return true;
} else {
return false;
}
}
template<typename T, typename U>
bool chmin(T& a, U b) {
if (a > b) {
a = b;
return true;
} else {
return false;
}
}
template<typename T>
void outspace(std::vector<T> a) {
int n = a.size();
for (int i = 0; i < n; ++i) {
std::cout << a[i];
if (i != n - 1) std::cout << " ";
else std::cout << std::endl;
}
}
void outspace(P a) {
std::cout << a.first << ' ' << a.second << '\n';
}
template<typename T>
void outendl(std::vector<T> a) {
int n = a.size();
for (int i = 0; i < n; ++i) {
std::cout << a[i] << '\n';
}
}
void outdouble(long double a) {
std::cout << std::fixed << std::setprecision(10) << a << std::endl;
}
std::vector<long long> lltovec(long long n, long long base = 10, long long minsize = -1) {
std::vector<long long> res;
while (minsize-- > 0 || n > 0) {
res.push_back(n % base);
n /= base;
}
// std::reverse(res.begin(), res.end());
return res;
}
long long vectoll(std::vector<long long> vec, long long base = 10) {
long long res = 0;
std::reverse(vec.begin(), vec.end());
for (auto i : vec) {
res *= base;
res += i;
}
std::reverse(vec.begin(), vec.end());
return res;
}
class uftree {
private:
std::vector<int> union_find_tree;
std::vector<int> rank;
std::vector<int> nodes_count;
public:
uftree (int uftree_size) {
union_find_tree.resize(uftree_size);
rank.resize(uftree_size);
nodes_count.resize(uftree_size);
for (int i = 0; i < uftree_size; ++i) {
union_find_tree[i] = i;
rank[i] = 0;
nodes_count[i] = 1;
}
}
int find (int n) {
if (union_find_tree[n] == n) return n;
else {
union_find_tree[n] = find(union_find_tree[n]);
return union_find_tree[n];
}
}
void unite (int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
if (rank[x] > rank[y]) {
union_find_tree[y] = union_find_tree[x];
nodes_count[x] += nodes_count[y];
} else {
union_find_tree[x] = union_find_tree[y];
nodes_count[y] += nodes_count[x];
if (rank[x] == rank[y]) rank[y]++;
}
}
bool connected (int x, int y) {
x = find(x);
y = find(y);
return x == y;
}
long long groupCount (int x) {
x = find(x);
return nodes_count[x];
}
};
class maxSegmentTree {
int n;
std::vector<long long> tree, lazy;
const long long MINI = -4e18;
public:
maxSegmentTree(int size) {
n = size;
tree.assign(4 * n, MINI);
lazy.assign(4 * n, MINI);
}
void push(int node, int start, int end) {
if (lazy[node] != MINI) {
// 遅延値を現在のノードに適用
tree[node] = std::max(tree[node], lazy[node]);
// 子ノードに遅延値を伝播
if (start != end) {
lazy[node * 2] = std::max(lazy[node * 2], lazy[node]);
lazy[node * 2 + 1] = std::max(lazy[node * 2 + 1], lazy[node]);
}
// 現在のノードの遅延値をクリア
lazy[node] = MINI;
}
}
void updateRange(int l, int r, long long value, int node = 1, int start = 0, int end = -1) {
if (end == -1) end = n - 1;
push(node, start, end);
if (start > r || end < l) {
// 完全に範囲外
return;
}
if (start >= l && end <= r) {
// 完全に範囲内
lazy[node] = value;
push(node, start, end);
return;
}
// 部分的に範囲が重なる場合
int mid = (start + end) / 2;
updateRange(l, r, value, node * 2, start, mid);
updateRange(l, r, value, node * 2 + 1, mid + 1, end);
tree[node] = std::max(tree[node * 2], tree[node * 2 + 1]);
}
long long queryRange(int l, int r, int node = 1, int start = 0, int end = -1) {
if (end == -1) end = n - 1;
push(node, start, end);
if (start > r || end < l) {
// 完全に範囲外
return MINI;
}
if (start >= l && end <= r) {
// 完全に範囲内
return tree[node];
}
// 部分的に範囲が重なる場合
int mid = (start + end) / 2;
long long leftQuery = queryRange(l, r, node * 2, start, mid);
long long rightQuery = queryRange(l, r, node * 2 + 1, mid + 1, end);
return std::max(leftQuery, rightQuery);
}
};
class sumSegmentTree {
int n;
std::vector<long long> tree, lazy;
public:
sumSegmentTree(int size) {
n = size;
tree.assign(4 * n, 0);
lazy.assign(4 * n, 0);
}
void push(int node, int start, int end) {
if (lazy[node] != 0) {
// 遅延値を現在のノードに適用
tree[node] += (end - start + 1) * lazy[node];
// 子ノードに遅延値を伝播
if (start != end) {
lazy[node * 2] += lazy[node];
lazy[node * 2 + 1] += lazy[node];
}
// 現在のノードの遅延値をクリア
lazy[node] = 0;
}
}
void updateRange(int l, int r, long long value, int node = 1, int start = 0, int end = -1) {
if (end == -1) end = n - 1;
push(node, start, end);
if (start > r || end < l) {
// 完全に範囲外
return;
}
if (start >= l && end <= r) {
// 完全に範囲内
lazy[node] += value;
push(node, start, end);
return;
}
// 部分的に範囲が重なる場合
int mid = (start + end) / 2;
updateRange(l, r, value, node * 2, start, mid);
updateRange(l, r, value, node * 2 + 1, mid + 1, end);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
long long queryRange(int l, int r, int node = 1, int start = 0, int end = -1) {
if (end == -1) end = n - 1;
push(node, start, end);
if (start > r || end < l) {
// 完全に範囲外
return 0;
}
if (start >= l && end <= r) {
// 完全に範囲内
return tree[node];
}
// 部分的に範囲が重なる場合
int mid = (start + end) / 2;
long long leftQuery = queryRange(l, r, node * 2, start, mid);
long long rightQuery = queryRange(l, r, node * 2 + 1, mid + 1, end);
return leftQuery + rightQuery;
}
long long lower_bound(int l, long long value, int node = 1, int start = 0, int end = -1, long long curval = 0) {
if (end == -1) {
end = n - 1;
push(node, start, end);
curval += queryRange(0, l - 1);
if (tree[node] < value + curval) return n;
}
if (start == end) {
if (tree[node] + curval < value) return start + 1;
else return start;
}
int mid = (start + end) / 2;
push(node * 2, start, mid);
push(node * 2 + 1, mid + 1, end);
if (tree[node * 2] + curval >= value) {
return lower_bound(l, value, node * 2, start, mid, curval);
} else {
curval += tree[node * 2];
return lower_bound(l, value, node * 2 + 1, mid + 1, end, curval);
}
}
};
static const long long MOD = 998244353;
static const int MAXN = 1000000; // 必要に応じて大きく設定
// 階乗・階乗逆元の配列
static long long fact[MAXN+1], invFact[MAXN+1];
// 繰り返し二乗法 (a^b mod M)
long long modpow(long long a, long long b, long long M) {
long long ret = 1 % M;
a %= M;
while (b > 0) {
if (b & 1) ret = (ret * a) % M;
a = (a * a) % M;
b >>= 1;
}
return ret;
}
// 前処理: 階乗と逆元のテーブルを作る
void initFactorials() {
// 階乗テーブル
fact[0] = 1;
for (int i = 1; i <= MAXN; i++) {
fact[i] = fact[i-1] * i % MOD;
}
// 階乗逆元テーブル
invFact[MAXN] = modpow(fact[MAXN], MOD - 2, MOD); // フェルマーの小定理で逆元を計算
for (int i = MAXN; i >= 1; i--) {
invFact[i-1] = invFact[i] * i % MOD;
}
}
// 組み合わせ数 C(n, r)
long long comb(int n, int r) {
if (r < 0 || r > n) return 0;
return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD;
}
vector<pair<long long, long long>> rlell(vector<long long> a) {
vector<pair<long long, long long>> res;
if (a.empty()) return res;
res.push_back({a[0], 1});
long long n = a.size();
for (int i = 1; i < n; ++i) {
if (a[i] == a[i - 1]) {
res.back().second++;
} else {
res.push_back({a[i], 1});
}
}
return res;
}
vector<pair<char, long long>> rlest(string a) {
vector<pair<char, long long>> res;
if (a.empty()) return res;
res.push_back({a[0], 1});
long long n = a.size();
for (int i = 1; i < n; ++i) {
if (a[i] == a[i - 1]) {
res.back().second++;
} else {
res.push_back({a[i], 1});
}
}
return res;
}
// vector<int> cl = {-1, 0, 1, 0, -1};
// vector<ll> cl = {-1, 0, 1, 1, 1, 0, -1, -1, -1, 0};
int main()
{
ll n;
cin >> n;
vector<vector<ll>> candidate;
vector<vector<ll>> def = {
{1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 0, 0, 0, 0},
{1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 0, 0, 1},
{0, 1, 1, 0, 0, 1, 1},
{1, 0, 1, 1, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 0, 1, 1}
};
vector<ll> frec(10, 0);
auto f = [&](auto && self, ll cur, ll cc) -> void {
if (cur == 10) {
bool flag = true;
vector<ll> seg(7, 0);
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 7; ++j) {
seg[j] += def[i][j] * frec[i];
}
}
ll use = seg[2] + seg[4];
if (use % 2 != 0) flag = false;
use /= 2;
if (!ckran(use - seg[6], frec[0] + 1)) flag = false;
seg[0] -= use - seg[6];
seg[1] -= use - seg[6];
seg[5] -= use - seg[6];
seg[6] = use;
if (!ckran(use - seg[4], frec[1] + 1)) flag = false;
seg[1] -= use - seg[4];
seg[2] -= use - seg[4];
seg[5] += use - seg[4];
seg[4] = use;
if (!ckran(seg[0] - use, frec[6] + 1)) flag = false;
seg[0] = use;
if (!ckran(use - seg[5], frec[7] + 1)) flag = false;
seg[5] = use;
if (!ckran(seg[3] - use, frec[9] + 1)) flag = false;
seg[3] = use;
if (seg[1] != use || seg[2] != use) flag = false;
if (flag) {
for (int i = cc; i <= 19; ++i) {
frec[8] += i - cc;
candidate.push_back(frec);
frec[8] -= i - cc;
}
}
return;
}
if (cur == 8) {
self(self, cur + 1, cc);
return;
}
for (int i = 0; i < 20 - cc; ++i) {
frec[cur] = i;
self(self, cur + 1, cc + i);
frec[cur] = 0;
}
};
f(f, 0, 0);
auto vec = lltovec(n);
ll vs = vec.size();
vec = lltovec(n, 10, 19);
ll ans = 2e18;
ll fc = 0;
vector<ll> pl(19, 1);
for (int i = 1; i < 19; ++i) {
pl[i] = pl[i - 1] * 10;
}
auto f2 = [&](auto && self, vector<ll> frec, ll cur, ll cn) -> void {
if (fc < vs) return;
if (cur == -1) {
chmin(ans, cn);
}
if (cn > n || cur > fc) {
for (int i = 0; i < 10; ++i) {
if (frec[i] > 0) {
frec[i]--;
cn += pl[cur] * i;
self(self, frec, cur - 1, cn);
break;
}
}
} else {
if (frec[vec[cur]] > 0 && !(cn == 0 && vec[cur] == 0)) {
if (cur == 18) cn += pl[18] * min(2LL, vec[cur]);
else cn += pl[cur] * vec[cur];
frec[vec[cur]]--;
self(self, frec, cur - 1, cn);
if (cur == 18) cn -= pl[18];
else cn -= pl[cur] * vec[cur];
frec[vec[cur]]++;
}
for (int i = vec[cur] + 1; i < 10; ++i) {
if (frec[i] > 0) {
if (cur == 18) cn += pl[18] * min(2, i);
else cn += pl[cur] * i;
frec[i]--;
self(self, frec, cur - 1, cn);
break;
}
}
}
};
// for (int i = 100; i < 110; ++i) {
// for (int j = 0; j < 10; ++j) {
// for (int k = 0; k < candidate[i][j]; ++k) {
// cout << j;
// }
// }
// cout << endl;
// }
for (int i = 0; i < (int)candidate.size(); ++i) {
for (int j = 0; j < 10; ++j) fc += candidate[i][j];
// if (candidate[i][0] == 6 && candidate[i][8] == 1 && candidate[i][9] == 6) {
// for (int j = 0; j < 10; ++j) {
// for (int k = 0; k < candidate[i][j]; ++k) {
// cout << j;
// }
// }
// cout << endl;
// }
f2(f2, candidate[i], fc - 1, 0);
fc = 0;
}
cout << ans << endl;
}