結果
問題 | No.886 Direct |
ユーザー |
![]() |
提出日時 | 2022-01-29 16:15:50 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 181 ms / 4,000 ms |
コード長 | 15,280 bytes |
コンパイル時間 | 1,287 ms |
コンパイル使用メモリ | 112,512 KB |
実行使用メモリ | 26,632 KB |
最終ジャッジ日時 | 2025-01-02 07:35:25 |
合計ジャッジ時間 | 4,222 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 32 |
ソースコード
#line 1 "number/test/multiple_moebius.yuki886.test.cpp"#define PROBLEM "https://yukicoder.me/problems/no/886"#line 2 "modint.hpp"#include <iostream>#include <set>#include <vector>// CUT begintemplate <int md> struct ModInt {#if __cplusplus >= 201402L#define MDCONST constexpr#else#define MDCONST#endifusing lint = long long;MDCONST static int mod() { return md; }static int get_primitive_root() {static int primitive_root = 0;if (!primitive_root) {primitive_root = [&]() {std::set<int> fac;int v = md - 1;for (lint i = 2; i * i <= v; i++)while (v % i == 0) fac.insert(i), v /= i;if (v > 1) fac.insert(v);for (int g = 1; g < md; g++) {bool ok = true;for (auto i : fac)if (ModInt(g).pow((md - 1) / i) == 1) {ok = false;break;}if (ok) return g;}return -1;}();}return primitive_root;}int val;MDCONST ModInt() : val(0) {}MDCONST ModInt &_setval(lint v) { return val = (v >= md ? v - md : v), *this; }MDCONST ModInt(lint v) { _setval(v % md + md); }MDCONST explicit operator bool() const { return val != 0; }MDCONST ModInt operator+(const ModInt &x) const { return ModInt()._setval((lint)val + x.val); }MDCONST ModInt operator-(const ModInt &x) const {return ModInt()._setval((lint)val - x.val + md);}MDCONST ModInt operator*(const ModInt &x) const {return ModInt()._setval((lint)val * x.val % md);}MDCONST ModInt operator/(const ModInt &x) const {return ModInt()._setval((lint)val * x.inv() % md);}MDCONST ModInt operator-() const { return ModInt()._setval(md - val); }MDCONST ModInt &operator+=(const ModInt &x) { return *this = *this + x; }MDCONST ModInt &operator-=(const ModInt &x) { return *this = *this - x; }MDCONST ModInt &operator*=(const ModInt &x) { return *this = *this * x; }MDCONST ModInt &operator/=(const ModInt &x) { return *this = *this / x; }friend MDCONST ModInt operator+(lint a, const ModInt &x) {return ModInt()._setval(a % md + x.val);}friend MDCONST ModInt operator-(lint a, const ModInt &x) {return ModInt()._setval(a % md - x.val + md);}friend MDCONST ModInt operator*(lint a, const ModInt &x) {return ModInt()._setval(a % md * x.val % md);}friend MDCONST ModInt operator/(lint a, const ModInt &x) {return ModInt()._setval(a % md * x.inv() % md);}MDCONST bool operator==(const ModInt &x) const { return val == x.val; }MDCONST bool operator!=(const ModInt &x) const { return val != x.val; }MDCONST bool operator<(const ModInt &x) const {return val < x.val;} // To use std::map<ModInt, T>friend std::istream &operator>>(std::istream &is, ModInt &x) {lint t;return is >> t, x = ModInt(t), is;}MDCONST friend std::ostream &operator<<(std::ostream &os, const ModInt &x) {return os << x.val;}MDCONST ModInt pow(lint n) const {ModInt ans = 1, tmp = *this;while (n) {if (n & 1) ans *= tmp;tmp *= tmp, n >>= 1;}return ans;}static std::vector<ModInt> facs, facinvs, invs;MDCONST static void _precalculation(int N) {int l0 = facs.size();if (N > md) N = md;if (N <= l0) return;facs.resize(N), facinvs.resize(N), invs.resize(N);for (int i = l0; i < N; i++) facs[i] = facs[i - 1] * i;facinvs[N - 1] = facs.back().pow(md - 2);for (int i = N - 2; i >= l0; i--) facinvs[i] = facinvs[i + 1] * (i + 1);for (int i = N - 1; i >= l0; i--) invs[i] = facinvs[i] * facs[i - 1];}MDCONST lint inv() const {if (this->val < std::min(md >> 1, 1 << 21)) {while (this->val >= int(facs.size())) _precalculation(facs.size() * 2);return invs[this->val].val;} else {return this->pow(md - 2).val;}}MDCONST ModInt fac() const {while (this->val >= int(facs.size())) _precalculation(facs.size() * 2);return facs[this->val];}MDCONST ModInt facinv() const {while (this->val >= int(facs.size())) _precalculation(facs.size() * 2);return facinvs[this->val];}MDCONST ModInt doublefac() const {lint k = (this->val + 1) / 2;return (this->val & 1) ? ModInt(k * 2).fac() / (ModInt(2).pow(k) * ModInt(k).fac()): ModInt(k).fac() * ModInt(2).pow(k);}MDCONST ModInt nCr(const ModInt &r) const {return (this->val < r.val) ? 0 : this->fac() * (*this - r).facinv() * r.facinv();}MDCONST ModInt nPr(const ModInt &r) const {return (this->val < r.val) ? 0 : this->fac() * (*this - r).facinv();}ModInt sqrt() const {if (val == 0) return 0;if (md == 2) return val;if (pow((md - 1) / 2) != 1) return 0;ModInt b = 1;while (b.pow((md - 1) / 2) == 1) b += 1;int e = 0, m = md - 1;while (m % 2 == 0) m >>= 1, e++;ModInt x = pow((m - 1) / 2), y = (*this) * x * x;x *= (*this);ModInt z = b.pow(m);while (y != 1) {int j = 0;ModInt t = y;while (t != 1) j++, t *= t;z = z.pow(1LL << (e - j - 1));x *= z, z *= z, y *= z;e = j;}return ModInt(std::min(x.val, md - x.val));}};template <int md> std::vector<ModInt<md>> ModInt<md>::facs = {1};template <int md> std::vector<ModInt<md>> ModInt<md>::facinvs = {1};template <int md> std::vector<ModInt<md>> ModInt<md>::invs = {0};// using mint = ModInt<998244353>;// using mint = ModInt<1000000007>;#line 2 "number/sieve.hpp"#include <cassert>#include <map>#line 5 "number/sieve.hpp"// CUT begin// Linear sieve algorithm for fast prime factorization// Complexity: O(N) time, O(N) space:// - MAXN = 10^7: ~44 MB, 80~100 ms (Codeforces / AtCoder GCC, C++17)// - MAXN = 10^8: ~435 MB, 810~980 ms (Codeforces / AtCoder GCC, C++17)// Reference:// [1] D. Gries, J. Misra, "A Linear Sieve Algorithm for Finding Prime Numbers,"// Communications of the ACM, 21(12), 999-1003, 1978.// - https://cp-algorithms.com/algebra/prime-sieve-linear.html// - https://37zigen.com/linear-sieve/struct Sieve {std::vector<int> min_factor;std::vector<int> primes;Sieve(int MAXN) : min_factor(MAXN + 1) {for (int d = 2; d <= MAXN; d++) {if (!min_factor[d]) {min_factor[d] = d;primes.emplace_back(d);}for (const auto &p : primes) {if (p > min_factor[d] or d * p > MAXN) break;min_factor[d * p] = p;}}}// Prime factorization for 1 <= x <= MAXN^2// Complexity: O(log x) (x <= MAXN)// O(MAXN / log MAXN) (MAXN < x <= MAXN^2)template <class T> std::map<T, int> factorize(T x) const {std::map<T, int> ret;assert(x > 0 andx <= ((long long)min_factor.size() - 1) * ((long long)min_factor.size() - 1));for (const auto &p : primes) {if (x < T(min_factor.size())) break;while (!(x % p)) x /= p, ret[p]++;}if (x >= T(min_factor.size())) ret[x]++, x = 1;while (x > 1) ret[min_factor[x]]++, x /= min_factor[x];return ret;}// Enumerate divisors of 1 <= x <= MAXN^2// Be careful of highly composite numbers https://oeis.org/A002182/list// https://gist.github.com/dario2994/fb4713f252ca86c1254d#file-list-txt (n, (# of div. of n)):// 45360->100, 735134400(<1e9)->1344, 963761198400(<1e12)->6720template <class T> std::vector<T> divisors(T x) const {std::vector<T> ret{1};for (const auto p : factorize(x)) {int n = ret.size();for (int i = 0; i < n; i++) {for (T a = 1, d = 1; d <= p.second; d++) {a *= p.first;ret.push_back(ret[i] * a);}}}return ret; // NOT sorted}// Euler phi functions of divisors of given x// Verified: ABC212 G https://atcoder.jp/contests/abc212/tasks/abc212_g// Complexity: O(sqrt(x) + d(x))template <class T> std::map<T, T> euler_of_divisors(T x) const {assert(x >= 1);std::map<T, T> ret;ret[1] = 1;std::vector<T> divs{1};for (auto p : factorize(x)) {int n = ret.size();for (int i = 0; i < n; i++) {ret[divs[i] * p.first] = ret[divs[i]] * (p.first - 1);divs.push_back(divs[i] * p.first);for (T a = divs[i] * p.first, d = 1; d < p.second; a *= p.first, d++) {ret[a * p.first] = ret[a] * p.first;divs.push_back(a * p.first);}}}return ret;}// Moebius function Table, (-1)^{# of different prime factors} for square-free x// return: [0=>0, 1=>1, 2=>-1, 3=>-1, 4=>0, 5=>-1, 6=>1, 7=>-1, 8=>0, ...] https://oeis.org/A008683std::vector<int> GenerateMoebiusFunctionTable() const {std::vector<int> ret(min_factor.size());for (unsigned i = 1; i < min_factor.size(); i++) {if (i == 1) {ret[i] = 1;} else if ((i / min_factor[i]) % min_factor[i] == 0) {ret[i] = 0;} else {ret[i] = -ret[i / min_factor[i]];}}return ret;}// Calculate [0^K, 1^K, ..., nmax^K] in O(nmax)// Note: **0^0 == 1**template <class MODINT> std::vector<MODINT> enumerate_kth_pows(long long K, int nmax) const {assert(nmax < int(min_factor.size()));assert(K >= 0);if (K == 0) return std::vector<MODINT>(nmax + 1, 1);std::vector<MODINT> ret(nmax + 1);ret[0] = 0, ret[1] = 1;for (int n = 2; n <= nmax; n++) {if (min_factor[n] == n) {ret[n] = MODINT(n).pow(K);} else {ret[n] = ret[n / min_factor[n]] * ret[min_factor[n]];}}return ret;}};// Sieve sieve((1 << 20));#line 3 "number/zeta_moebius_transform.hpp"#include <algorithm>#line 5 "number/zeta_moebius_transform.hpp"#include <utility>#line 7 "number/zeta_moebius_transform.hpp"// f[n] に対して、全ての n の倍数 n*i に対する f[n*i] の和が出てくる 計算量 O(N loglog N)// 素数p毎に処理する高速ゼータ変換// 使用例 https://yukicoder.me/submissions/385043template <class T> void multiple_zeta(std::vector<T> &f) {int N = int(f.size()) - 1;std::vector<int> is_prime(N + 1, 1);for (int p = 2; p <= N; p++) {if (is_prime[p]) {for (int q = p * 2; q <= N; q += p) is_prime[q] = 0;for (int j = N / p; j > 0; --j) f[j] += f[j * p];}}}// inverse of multiple_zeta O(N loglog N)// 使用例 https://yukicoder.me/submissions/385120template <class T> void multiple_moebius(std::vector<T> &f) {int N = int(f.size()) - 1;std::vector<int> is_prime(N + 1, 1);for (int p = 2; p <= N; p++) {if (is_prime[p]) {for (int q = p * 2; q <= N; q += p) is_prime[q] = 0;for (int j = 1; j * p <= N; ++j) f[j] -= f[j * p];}}}// f[n] に関して、全ての n の約数 m に対する f[m] の総和が出てくる 計算量 O(N loglog N)template <class T> void divisor_zeta(std::vector<T> &f) {int N = int(f.size()) - 1;std::vector<int> is_prime(N + 1, 1);for (int p = 2; p <= N; ++p) {if (is_prime[p]) {for (int q = p * 2; q <= N; q += p) is_prime[q] = 0;for (int j = 1; j * p <= N; ++j) f[j * p] += f[j];}}}// inverse of divisor_zeta()template <class T> void divisor_moebius(std::vector<T> &f) {int N = int(f.size()) - 1;std::vector<int> is_prime(N + 1, 1);for (int p = 2; p <= N; ++p) {if (is_prime[p]) {for (int q = p * 2; q <= N; q += p) is_prime[q] = 0;for (int j = N / p; j > 0; --j) f[j * p] -= f[j];}}}// GCD convolution// ret[k] = \sum_{gcd(i, j) = k} f[i] * g[j]template <class T> std::vector<T> gcdconv(std::vector<T> f, std::vector<T> g) {assert(f.size() == g.size());multiple_zeta(f);multiple_zeta(g);for (int i = 0; i < int(g.size()); ++i) f[i] *= g[i];multiple_moebius(f);return f;}// LCM convolution// ret[k] = \sum_{lcm(i, j) = k} f[i] * g[j]template <class T> std::vector<T> lcmconv(std::vector<T> f, std::vector<T> g) {assert(f.size() == g.size());divisor_zeta(f);divisor_zeta(g);for (int i = 0; i < int(g.size()); ++i) f[i] *= g[i];divisor_moebius(f);return f;}// fast_integer_moebius の高速化(登場しない素因数が多ければ計算量改善)// Requirement: f の key として登場する正整数の全ての約数が key として登場// Verified: https://toph.co/p/height-of-the-treestemplate <typename Int, typename Val>void sparse_fast_integer_moebius(std::vector<std::pair<Int, Val>> &f, const Sieve &sieve) {if (f.empty()) return;std::sort(f.begin(), f.end());assert(f.back().first < Int(sieve.min_factor.size()));std::vector<Int> primes;for (auto p : f) {if (sieve.min_factor[p.first] == p.first) primes.push_back(p.first);}std::vector<std::vector<int>> p2is(primes.size());for (int i = 0; i < int(f.size()); i++) {Int a = f[i].first, pold = 0;int k = 0;while (a > 1) {auto p = sieve.min_factor[a];if (p != pold) {while (primes[k] != p) k++;p2is[k].emplace_back(i);}pold = p, a /= p;}}for (int d = 0; d < int(primes.size()); d++) {Int p = primes[d];for (auto i : p2is[d]) {auto comp = [](const std::pair<Int, Val> &l, const std::pair<Int, Val> &r) {return l.first < r.first;};auto itr = std::lower_bound(f.begin(), f.end(), std::make_pair(f[i].first / p, 0), comp);itr->second -= f[i].second;}}}#line 7 "number/test/multiple_moebius.yuki886.test.cpp"using namespace std;using mint = ModInt<1000000007>;int main() {int H, W;cin >> H >> W;int N = max(H, W);vector<mint> dp(N);auto calc = [&](int n, int W) -> mint {// 2 * ((W - n) + (W - 2 * n) + ...)mint k = W / n;return W * k * 2 - k * (k + 1) * n;};for (int n = 1; n < N; ++n) {mint n1 = calc(n, H), n2 = calc(n, W);dp[n] = (n1 + H) * (n2 + W) - mint(H) * W;}multiple_moebius(dp);cout << dp[1] / 2 << '\n';}