絶滅

どうでもいい

分割数を三通りの方法で求めるやつ

はい

#include "bits/stdc++.h"

// space: O(n^2), time: O(n^3)
// n ~ 2000
class PartitionNumberN3 {
  using ll = long long;
  ll rec(ll n, ll k) {
    if (dp[n][k] != -1) return dp[n][k];
    ll ret = 0;
    for (ll i = 0; i <= k; i++)
      ret += rec(n - k + i, std::min(n - k + i, k - i));
    return dp[n][k] = ret % MOD;
  }
public:
  const ll MOD = 1000000007;
  ll n;
  ll** dp; // dp[n][k]: n を k 以下の和で表す場合の数
  PartitionNumberN3(ll n) : n(n) {
    dp = new ll*[n + 1];
    for (ll i = 0; i <= n; i++) dp[i] = new ll[n + 1];
    for (ll i = 0; i <= n; i++) for (ll j = 0; j <= n; j++) dp[i][j] = -1;
    for (ll i = 0; i <= n; i++) dp[0][i] = 1;
    for (ll i = 1; i <= n; i++) dp[i][0] = 0;
    rec(n, n);
  }
  ~PartitionNumberN3() {
    for (ll i = 0; i <= n; i++) delete[] dp[i];
    delete[] dp;
  }

  ll getAns() {
    return dp[n][n];
  }
};

// space: O(n^2), time: O(n^2)
// n ~ 20000
class PartitionNumberN2 {
  using ll = long long;
public:
  const ll MOD = 1000000007;
  ll n;
  ll** dp; // dp[n][k]: n を k 個以下に分割する場合の数
  PartitionNumberN2(ll n) : n(n) {
    dp = new ll*[n + 1];
    for (ll i = 0; i <= n; i++) dp[i] = new ll[n + 1];
    for (ll i = 0; i <= n; i++) dp[i][0] = 0;
    for (ll i = 0; i <= n; i++) dp[0][i] = 1;
    for (ll i = 1; i <= n; i++) for (ll j = 1; j <= n; j++)
      dp[i][j] = (dp[i][j - 1] + (i >= j ? dp[i - j][j] : 0)) % MOD;
  }
  ~PartitionNumberN2() {
    for (ll i = 0; i <= n; i++) delete[] dp[i];
    delete[] dp;
  }

  ll getAns() {
    return dp[n][n];
  }
};

// https://en.wikipedia.org/wiki/Pentagonal_number_theorem
// space: O(n), time: O(n sqrt(n))
// n ~ 1000000
class PartitionNumberNsqrtN {
  using ll = long long;
  inline ll gp(ll k) { return k * (3 * k - 1) / 2; }
public:
  const ll MOD = 1000000007;
  ll n;
  ll* p;
  PartitionNumberNsqrtN(ll n) : n(n) {
    p = new ll[n + 1];
    p[0] = 1;
    ll maxcnt = 0;
    for (ll i = 1; i <= n; i++) {
      p[i] = 0;
      for (ll j = 1;; j += 2) {
        ll k = gp(j); if (k > i) break;
        p[i] += p[i - k];
        k = gp(-j); if (k > i) break;
        p[i] += p[i - k];
        k = gp(j + 1); if (k > i) break;
        p[i] -= p[i - k];
        k = gp(-j - 1); if (k > i) break;
        p[i] -= p[i - k];
      }
      p[i] %= MOD;
    }
  }
  ~PartitionNumberNsqrtN() {
    delete[] p;
  }

  ll getAns() {
    return (p[n] + MOD) % MOD;
  }
};

int main() {
  using ll = long long;
  ll N = 1000;

  PartitionNumberN3 pn1(N);
  PartitionNumberN2 pn2(N);
  PartitionNumberNsqrtN pn3(N);

  std::cout << pn1.getAns() << std::endl;
  std::cout << pn2.getAns() << std::endl;
  std::cout << pn3.getAns() << std::endl;

  return 0;
}