#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>
#include <initializer_list>
#include <ostream>
#include <iterator>
#include <fstream>
using namespace std;
namespace fast_scanner {
static char ibuf[1 << 20], *p1 = ibuf, *p2 = ibuf;
bool advance() { return p2 = (p1 = ibuf) + fread(ibuf, 1, sizeof(ibuf), stdin), (p1 == p2); }
char gc() { return (p1 == p2 && advance()) ? EOF : (*p1++); }
void put_back() { p1--; }
static bool isspace(char c) { return static_cast<unsigned char>(c - '\t') < 5 || c == ' '; }
static bool isdigit(char c) { return static_cast<unsigned char>(c - '0') < 10; }
static inline bool isoneof(char c, const char *str) { return strchr(str, c) != nullptr; }
template <const char *str> static inline bool isoneof(char c) { return strchr(str, c) != nullptr; }
uint64_t read_ull() {
    char ch = gc();
    while (!isdigit(ch)) {
        ch = gc();
    }
    uint64_t res = 0;
    while (isdigit(ch)) {
        res = res * 10 + (ch - '0'), ch = gc();
    }
    return res;
}
int64_t read_ll() {
    char ch = gc();
    bool neg = false;
    while (!isdigit(ch)) {
        neg |= (ch == '-'), ch = gc();
    }
    uint64_t res = 0;
    while (isdigit(ch)) {
        res = res * 10 + (ch - '0'), ch = gc();
    }
    neg && (res = -res);
    return res;
}
long double read_ld() {
    char ch = gc();
    bool neg = false;
    while (!isdigit(ch)) {
        neg |= (ch == '-'), ch = gc();
    }
    uint64_t integerPart = 0, fractionalPart = 0, len = 0, base = 1;
    while (isdigit(ch)) {
        integerPart = integerPart * 10 + (ch - '0'), ch = gc();
    }
    if (ch == '.') {
        ch = gc();
        while (isdigit(ch)) {
            fractionalPart = fractionalPart * 10 + (ch - '0'), ch = gc(), len += 1;
        }
        while (len--)
            base *= 10;
    }
    long double res = (long double)integerPart + (long double)fractionalPart / base;
    neg && (res = -res);
    return res;
}
string read_delim(const char *str) {
    char ch = gc();
    while (isoneof(ch, str))
        ch = gc();
    string res;
    while (!isoneof(ch, str))
        res += ch, ch = gc();
    return res;
}
template <typename UnaryPredicate> string read_delim(UnaryPredicate predicate) {
    char ch = gc();
    while (predicate(ch))
        ch = gc();
    string res;
    while (!predicate(ch))
        res += ch, ch = gc();
    return res;
}
string read_line() {
    return read_delim([](char ch) {
        return ch == '\n';
    });
}
string read_string() { return read_delim(isspace); }
char read_char() { return gc(); }
int read_int() { return (int)read_ll(); }
void skip_whitespace() {
    char ch = gc();
    while (isspace(ch))
        ch = gc();
    put_back();
}
}
template <typename T> T scan();
template <> int scan<int>() { return fast_scanner::read_int(); }
template <> long scan<long>() { return (long)fast_scanner::read_ll(); }
template <> long long scan<long long>() { return fast_scanner::read_ll(); }
template <> long double scan<long double>() { return fast_scanner::read_ld(); }
template <> double scan<double>() { return (double)fast_scanner::read_ld(); }
template <> string scan<string>() { return fast_scanner::read_string(); }
template <> char scan<char>() { return fast_scanner::gc(); }
void scan() { fast_scanner::skip_whitespace(); }
template <typename A, typename B> pair<A, B> scan() {
    auto a = scan<A>();
    auto b = scan<B>();
    return make_pair(a, b);
}
template<typename A, typename B, typename C> tuple<A, B, C> scan() {
    auto a = scan<A>();
    auto b = scan<B>();
    auto c = scan<C>();
    return make_tuple(a, b, c);
}
template <typename A, typename B, typename C, typename D, typename... Args> tuple<A, B, C, Args...> scan() {
    auto a = make_tuple(scan<A>());
    auto b = scan<B, C, D, Args...>();
    return tuple_cat(a, b);
}
template <typename T, size_t U> array<T, U> scan() {
    array<T, U> res;
    for (int i = 0; i < U; ++i)
        res[i] = scan<T>();
    return res;
}
template <typename T> vector<T> scan(int n, int s = 0) {
    vector<T> res(n + s);
    for (int i = 0; i < n; ++i) {
        res[i + s] = scan<T>();
    }
    return res;
}
template <typename A, typename B> vector<pair<A, B>> scan(int n, int s = 0) {
    vector<pair<A, B>> res(n + s);
    for (int i = 0; i < n; ++i) {
        res[i + s] = scan<A, B>();
    }
    return res;
}
template <typename A, typename B, typename C, typename... Args> vector<tuple<A, B, C, Args...>> scan(int n, int s = 0) {
    vector<tuple<A, B, C, Args...>> res(n + s);
    for (int i = 0; i < n; ++i) {
        res[i + s] = scan<A, B, C, Args...>();
    }
    return res;
}
template <typename T, size_t U> vector<array<T, U>> scan(int n, int s = 0) {
    vector<array<T, U>> res(n + s);
    for (int i = 0; i < U; ++i)
        res[i + s] = scan<T, U>();
    return res;
}
template <typename T, size_t X> void ctvl(T (&a)[X], const T &v) { fill_n(&a[0], X, v); }
template <typename T, size_t X, size_t Y> void ctvl(T (&a)[X][Y], const T &v) { fill_n(&a[0][0], X * Y, v); }
template <typename T, size_t X, size_t Y, size_t Z> void ctvl(T (&a)[X][Y][Z], const T &v) { fill_n(&a[0][0][0], X * Y * Z, v); }
template <typename T, size_t X, size_t Y, size_t Z, size_t W> void ctvl(T (&a)[X][Y][Z][W], const T &v) { fill_n(&a[0][0][0][0], X * Y * Z * W, v); }
template <typename T> T read() { T x; cin >> x; return x; }
template <typename... Args> void writeln(const Args &... args) { ((cout << args << " "), ...), cout << endl; }
template <typename... Args> void write(const Args &... args) { ((cout << args), ...); }
template <typename T> typename enable_if<is_same<decltype(declval<T>().size()), size_t>::value, int>::type operator~(const T &ct) { return (int)ct.size(); }
template <typename T, typename... Args> bool ckmax(T &a, const Args &... b) { return (a < max({b...})) ? (a = max({b...}), true) : false; }
template <typename T, typename... Args> bool ckmin(T &a, const Args &... b) { return (a > min({b...})) ? (a = min({b...}), true) : false; }
template <typename T> T div_floor(const T &a, const T &b) { return (a / b) - (!!(a % b) & ((a ^ b) < 0)); }
template <typename T> T div_ceil(const T &a, const T &b) { return (a / b) + (!!(a % b) & ((a ^ b) > 0)); }
template <typename T> using min_heap = priority_queue<T, vector<T>, greater<T>>;
template <typename T> using max_heap = priority_queue<T, vector<T>, less<T>>;
template <typename T, typename... Args, template <typename, typename...> typename Container> Container<T, Args...> &operator+=(Container<T, Args...> &ct, const T &val) { return ct.push_back(val), ct; }
template <typename T, typename... Args, template <typename, typename...> typename Container> Container<T, Args...> &operator+=(const T &val, Container<T, Args...> &ct) { return ct.push_front(val), ct; }
template <typename T, typename... Args, template <typename, typename...> typename Container> T &operator+(Container<T, Args...> &ct) { return *ct.begin(); }
template <typename T, typename... Args, template <typename, typename...> typename Container> T &operator-(Container<T, Args...> &ct) { return *prev(ct.end()); }
template <typename T, typename... Args, template <typename, typename...> typename Container> T operator--(Container<T, Args...> &ct) { auto res = *ct.begin(); return ct.erase(ct.begin()), res; }
template <typename T, typename... Args, template <typename, typename...> typename Container> T operator--(Container<T, Args...> &ct, int) { auto res = *prev(ct.end()); return ct.erase(prev(ct.end())), res; }
template <typename T, typename... Args, template <typename, typename...> typename Container> int lbi(const Container<T, Args...> &ct, const T &val) { return (int)(lower_bound(ct.begin(), ct.end(), val) - ct.begin()); }
template <typename T, typename... Args, template <typename, typename...> typename Container> int ubi(const Container<T, Args...> &ct, const T &val) { return (int)(upper_bound(ct.begin(), ct.end(), val) - ct.begin()); }
template <int D, typename T> struct vecnd : public vector<vecnd<D - 1, T>> {
    template <typename... Args> vecnd(int n, Args... args) : vector<vecnd<D - 1, T>>(n, vecnd<D - 1, T>(args...)) {}
    void fill(const T &val = T()) {
        for (auto &it : *this)
            it.fill(val);
    }
    bool bounds_check(int i) { return (i >= 0) and (i < (int)this->size()); }
    template <typename... Args> bool bounds_check(int i, Args... args) {
        return (i >= 0) and (i < (int)this->size()) and (this->at(i).bounds_check(args...));
    }
};
template <typename T> struct vecnd<1, T> : public vector<T> {
    vecnd(int n, const T &val = T()) : vector<T>(n, val) {}
    void fill(const T &val = T()) {
        for (auto &it : *this)
            it = val;
    }
    bool bounds_check(int i) { return (i >= 0) and (i < (int)this->size()); }
};
template <typename T> using V = vecnd<1, T>;
template <typename T> using VV = vecnd<2, T>;
template <typename T> using VVV = vecnd<3, T>;
vector<pair<int, int>> dirs = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
vector<pair<int, int>> edirs = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
template <typename K, typename V> pair<K, V> operator+(const pair<K, V> &a, const pair<K, V> &b) { return {a.first + b.first, a.second + b.second}; }
template <typename K, typename V> pair<K, V> operator-(const pair<K, V> &a, const pair<K, V> &b) { return {a.first - b.first, a.second - b.second}; }
template <typename K, typename V> pair<K, V>& operator+=(pair<K, V> &a, const pair<K, V> &b) { return a = a + b; }
template <typename K, typename V> pair<K, V>& operator-=(pair<K, V> &a, const pair<K, V> &b) { return a = a - b; }
template <typename T> struct range { T u, v;
    range(const T &_u, const T &_v) : u(_u), v(_v) {}
    bool has(const T &w) { return (u <= w) and (w < v); }
    bool has_incl(const T &w) { return (u <= w) and (w <= v); }
};
int log2_floor(uint32_t n) { return 31 - __builtin_clz(n); }
int log2_ceil(uint32_t n) { return log2_floor(n) + !!(n & (n - 1)); }
       
template <typename T> using vv = vector<vector<T>>;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
const long long md = 924844033;
auto soln() {
    auto [n, k] = scan<long long, long long>();
    vector<long long> fact(n + 1, 1);
    for (long long i = 1; i <= (long long)(n); ++i) (fact[i] = fact[i - 1] * i) %= md;
    vector<long long> L(k + 1);
    for (long long i = 1; i <= k; ++i) {
        for (long long j = i; j <= n; j +=k) L[i] += 1;
    }
    VV<long long> W(n + 1, 2*k + 1, -1), F(n + 1, n + 1, -1);
    function<long long(long long nj, long long mj)> path_match = [&](long long nj, long long mj) -> long long {
        ;;
        long long& res = F[nj][mj];
        if (mj > nj / 2) return res=0;
        if (mj == 0) return res=1;
        if (res != -1) return res;
        return (res = path_match(nj - 2, mj - 1) + path_match(nj - 1, mj)) %= md;
    };
    for (long long i = 0; i < (long long)(n + 1); ++i) for (long long j = 0; j < (long long)(n + 1); ++j) path_match(i, j);
    function<long long(long long m, long long j)> matchings = [&](long long m, long long j) -> long long {
        ;;
        if (j > 2*k) return m == 0;
        long long &res = W[m][j];
        if (res != -1) return res;
        res = 0;
        long long nj = (j > k) ? L[j - k] : L[j];
        for (long long mj = 0; mj <= min(m, nj/2); ++mj) {
            (res += (F[nj][mj] * matchings(m - mj, j + 1)) % md) %= md;
        }
        return res;
    };
    long long res = fact[n], par=-1;
    for(long long m = 1; m <= n; ++m) {
        (res += (par*fact[n-m]*matchings(m, 1))%md)%=md, par *= -1;
    }
    ;; ;; ;; ;;
    cout << ((res+md)%md) << "\n";
}
signed main() {
    long long t = 1;
    ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
    while (t--)
        soln();
    return 0;
}


Measured memory_bytes: 97584