結果
| 問題 | No.3416 マッチ棒パズル Extra |
| コンテスト | |
| ユーザー |
Kude
|
| 提出日時 | 2025-12-23 23:26:22 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 5,521 bytes |
| 記録 | |
| コンパイル時間 | 4,041 ms |
| コンパイル使用メモリ | 370,948 KB |
| 実行使用メモリ | 19,408 KB |
| 最終ジャッジ日時 | 2025-12-23 23:26:35 |
| 合計ジャッジ時間 | 12,809 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | TLE * 1 -- * 25 |
ソースコード
#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision;
using u256 = boost::multiprecision::uint256_t;
// using u128 = boost::multiprecision::uint128_t;
using u128 = uint128_t;
// using ull = boost::multiprecision::number<cpp_int_backend<64, 64, unsigned_magnitude, unchecked, void> >;
using ull = unsigned long long;
#include <atcoder/modint>
using namespace atcoder;
using mint = modint998244353;
// https://259-momone.hatenablog.com/entry/2021/07/25/025655
#include<iostream>
#include<vector>
#include<tuple>
#include<cmath>
using namespace std;
template<typename Integer, typename Result = Integer>
constexpr Result sqrt_floor(const Integer& n){
if(n <= 1)return n;
Integer r(sqrt(n));
do r = (r & n / r) + (r ^ n / r) / 2; while(r > n / r);
return r;
}
template<typename Integer>
constexpr bool is_inside(const Integer& x, const Integer& y, const Integer& n){
// (2x+1)(2y+1) >= 2n
using ull0 = unsigned long long;
ull0 z;
if (__builtin_mul_overflow(ull0(2*x+1), ull0(2*y+1), &z)) return true;
return z >= 2*n;
}
template<typename Integer>
constexpr bool is_cross(const Integer& x, const Integer& y, const Integer& a, const Integer& b, const Integer& n){
// if(a == 0 || b == 0)return a * y > b * x;
// (x+1/2)(y+1/2) >= n/2
assert(a > 0);
if (b == 0) {
// y > -1/2
return y >= 0;
}
// (b(2x+1)+a(2y+1))^2 <= 8abn
auto lhs = u128(b) * (2 * x + 1) + u128(a) * (2 * y + 1);
auto rhs = u256(8 * b) * (u128(a) * n);
auto lhs2 = u256(lhs) * lhs;
if (lhs2 < rhs) return false;
return u128(a) * (2 * y + 1) > u128(b) * (2 * x + 1);
}
constexpr ull next_in(const ull& x, const ull& y, const ull& a, const ull& b, const ull& n){
assert(a > 0);
if (b == 0) {
assert(a == 1);
// ceil((2n-2y-1)/(4y+2)) - x
return (n + y) / (2 * y + 1) - x;
}
// if(b == 0)return (n - x * y + a * y - 1) / (a * y);
auto lhs = u128(b) * (2 * x + 1) + u128(a) * (2 * y + 1);
auto rhs = u256(8 * b) * (u128(a) * n);
auto D = u256(lhs) * lhs - rhs;
using namespace std;
auto denom = 4 * a * u128(b);
assert(denom > 0);
auto res = (a * u128(2 * y + 1) + denom - 1 - b * u128(2 * x + 1) - boost::multiprecision::sqrt(D)) / denom;
return (ull)(res);
// return (a * y - sqrt_floor<__uint128_t, ull>(static_cast<__uint128_t>(b * x + a * y) * (b * x + a * y) - static_cast<__uint128_t>(4) * a * b * n) - b * x + 2 * a * b - 1) / (2 * a * b);
}
constexpr ull next_out(const ull& x, const ull& y, const ull& a, const ull& b, const ull& n){
assert(b > 0);
if (a == 0) {
assert(b == 1);
return y - (n + x) / (2 * x + 1);
}
// if(a == 0)return (x * y - n) / (x * b);
auto lhs = u128(b) * (2 * x + 1) + u128(a) * (2 * y + 1);
auto rhs = u256(8 * b) * (u128(a) * n);
auto D = u256(lhs) * lhs - rhs;
auto denom = 4 * a * u128(b);
assert(denom > 0);
auto res = (a * u128(2 * y + 1) + boost::multiprecision::sqrt(D) - b * u128(2 * x + 1)) / denom;
return (ull)(res);
}
template<typename Integer>
mint count_divisors(const Integer& X){
using namespace std;
using integer_type = Integer;
using subtree_type = std::tuple<integer_type, integer_type, integer_type, integer_type>;
vector<subtree_type> stern_brocot_tree{{1, 0, 0, 1}, {0, 1, 0, 0}};
using point_type = std::pair<integer_type, integer_type>;
auto LMT = (2*X-3+5)/6;
auto V = ((unsigned long long)sqrtl((unsigned long long)(2*X))-1)/2;
point_type now_point{V+1, (-2*V+2*X-3+4*V+5)/(4*V+6)};
mint result{int((now_point.second - 1) % mint::mod())};
while(now_point.first <= LMT){
auto& [x, y]{now_point};
// subtree between a/b and c/d
auto [a, b, c, d]{stern_brocot_tree.back()};
stern_brocot_tree.pop_back();
if(b == 0)break;
// next vertex of convex hull
const auto n_upper{next_out(x, y, a, b, X)};
result += mint::raw(int((u128(a * n_upper) * y - (u128(a * n_upper + 1) * (b * n_upper + 1) + n_upper) / 2) % mint::mod()));
x += n_upper * a;
y -= n_upper * b;
// backtrack
while(!empty(stern_brocot_tree)){
tie(a, b, c, d) = stern_brocot_tree.back();
if(is_inside(x + a, y - b, X))break;
stern_brocot_tree.pop_back();
}
if(empty(stern_brocot_tree))break;
// search forward
while(y > d){
if(y > b + d && is_inside(x + a + c, y - b - d, X)){
const auto n_lower{next_out(x + a + c, y - b - d, c, d, X)};
tie(a, b, c, d) = make_tuple(a + c * (n_lower + 1), b + d * (n_lower + 1), a + c * (n_lower + 2), b + d * (n_lower + 2));
}else if(is_cross(x + c, y - d, a, b, X)){
const auto n_lower{next_in(x + c, y - d, a, b, X)};
if(y < b * n_lower + d || !is_inside(x + a * n_lower + c, y - b * n_lower - d, X)) break;
tie(a, b, c, d) = make_tuple(a * n_lower + c, b * n_lower + d, a * (n_lower - 1) + c, b * (n_lower - 1) + d);
}else break;
stern_brocot_tree.emplace_back(a, b, c, d);
}
}
return 2 * result + mint(V).pow(2);
}
int main(){
using namespace std;
using integer_type = ull;
int tt;
cin >> tt;
while (tt--) {
integer_type N;
// unsigned long long N;
cin >> N;
auto ans = count_divisors(N + 1);
cout << ans.val() << '\n';
}
}
Kude