Niuke multi school 9 A Math Challenge

Algorithm label

Geometric meaning of Euclidean like, equal power summation, Lagrange interpolation, Bernoulli number

thinking

Rectangular point weight sum, ∑ i = 0 n i p ∑ j = 1 k j q \sum_{i=0}^ni^p\sum_{j=1}^kj^q ∑ i=0n ∑ ip ∑ j=1k ∑ jq two independent summation and multiplication, equal power summation, natural number power, classical practice, polynomial interpolation, formula method, difference method, etc O ( p ) O(p) O(p)​

Point weight sum of right angled trapezoid

Because the translation occurs during the recursive subproblem, the sum of the point weight of the subproblem and the sum of the point weight of the original problem are not equal. At this time, notice that f ( i , j ) = i p j q f(i,j)=i^pj^q f(i,j)=ipjq is essentially a binary function, so we define a mapping for binary functions: T : P ( i , j ) → Q ( i , j ) T:P(i,j)\rightarrow Q(i,j) T:P(i,j)→Q(i,j)

For a point weight sum formula F = ∑ i ∑ j P ( i , j ) ⇒ T ( F ) = ∑ i ∑ j Q ( i , j ) F=\sum_i\sum_jP(i,j)\Rightarrow T(F)=\sum_i\sum_jQ(i,j) F=∑i​∑j​P(i,j)⇒T(F)=∑i​∑j​Q(i,j)

set up a n s = f a , b , c , n ( i , j ) ans=f_{a,b,c,n}(i,j) Definition of the Euclidean problem of ans=fa,b,c,n (i,j)

Consider the problem of Euclidean recursion

Case1

If b ≥ c b\geq c b ≥ c, then set $k=\lfloor \frac{b}{c}\rfloor $

Follow the European model and calculate it first f a , ( b m o d    c ) , c , n f_{a,(b\mod c),c,n} fa,(bmodc),c,n, but actually the calculation is to translate the upper trapezoid down and x x The point weight sum after the x-axis is aligned, so we want to apply a change to it T 1 : i p j q → i p ( j + k ) q T_1:i^pj^q \rightarrow i^p(j+k)^q T1: ipjq → ip(j+k)q, translate the ordinate of each position k k k units

Therefore:
f a , b , c , n ( p , q ) = ∑ i = 0 n i p ∑ j = 1 k j q + T 1 ( f a , ( b m o d    c ) , c , n ) ( p , q ) f_{a,b,c,n}(p,q)=\sum_{i=0}^ni^p\sum_{j=1}^kj^q+T_1(f_{a,(b\mod c),c,n})(p,q) fa,b,c,n​(p,q)=i=0∑n​ipj=1∑k​jq+T1​(fa,(bmodc),c,n​)(p,q)
Expand using binomial theorem:

i p ( j + k ) q = ∑ t = 0 q ( q t ) k q − t i p j t i^p(j+k)^q=\sum_{t=0}^q\dbinom{q}{t}k^{q-t}i^pj^t ip(j+k)q=t=0∑q​(tq​)kq−tipjt
So we get:
f a , b , c , n ( p , q ) = S r + ∑ t = 0 q ( q t ) f a , ( b m o d    c ) , c , n ( p , t ) f_{a,b,c,n}(p,q)=S_r+\sum_{t=0}^q\dbinom{q}{t}f_{a,(b\mod c),c,n}(p,t) fa,b,c,n​(p,q)=Sr​+t=0∑q​(tq​)fa,(bmodc),c,n​(p,t)
among S r S_r Sr , is the area of a rectangle. Pay attention to the boundary problem

Case2

If a ≥ c a\geq c a ≥ c, then set k = ⌊ a c ⌋ k=\lfloor \frac{a}{c} \rfloor k=⌊ca​⌋

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ctzbnw1p-1628972388840) (C: \ users \ Huhu \ appdata \ roaming \ typora user images \ image-20210815022358058. PNG)]

It's equivalent to cutting a right triangle out first, and the sum of the weight of this part is S t = ∑ i = 0 n ∑ j = 1 k i i p j q S_t=\sum_{i=0}^n\sum_{j=1}^{ki}i^pj^q St​=∑i=0n​∑j=1ki​ipjq

We change the point on the plane ( i , j ) → ( i , j − k i ) (i,j) \rightarrow (i,j-ki) (i,j) → (i,j − ki), so the trapezoid above the triangle becomes close x x The point weight sum of the right angle trapezoid on the x axis is f ( a m o d    c ) , b , c , n f_{(a\mod c),b,c,n} f(amodc),b,c,n​

With Case1, we also need to change the point back to the original position, and the corresponding point weight change is T 2 : i p j q → i p ( j + k i ) q T_2:i^pj^q \rightarrow i^p(j+ki)^q T2​:ipjq→ip(j+ki)q

Expand using binomial theorem:
f a , b , c , n ( p , q ) = S t + ∑ t = 0 q ( q t ) k q − t f ( a m o d    c ) , b , c , n ( p + q − t , t ) f_{a,b,c,n}(p,q)=S_t+\sum_{t=0}^q \dbinom{q}{t}k^{q-t}f_{(a\mod c), b,c,n}(p + q - t, t) fa,b,c,n​(p,q)=St​+t=0∑q​(tq​)kq−tf(amodc),b,c,n​(p+q−t,t)

Case3

If a < c a<c A < C and b < c b<c B < C, at this time, we can't cut a right triangle or a rectangle with side length greater than 1, so according to the routine, we will follow the plane y = x y=x y=x flip.

After flipping, the problem is transformed into the point weight sum of the rectangle minus the point weight sum of the triangle

[external chain picture transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-oa3nz9yl-1628972388843) (C: \ users \ Huhu \ appdata \ roaming \ typora user images \ image-20210815023316027. PNG)] [external chain picture transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-j7hcwl1s-1628972388844)(C:\Users\huhu\AppData\Roaming\Typora\typora-user-images\image-20210815023326010.png)]

At this time, we translate the whole graph to the left by one unit (equivalent to translating the y-axis to the right, because we notice that the intercept of the triangle is negative and need to change it to a positive number)

order m = ⌊ a n + b c ⌋ m=\lfloor\frac{an+b}{c}\rfloor m = ⌊ can+b ⌋, actually equal to y = a x + b c y=\frac{ax+b}{c} y=cax+b + x = n x=n The largest whole point under the intersection of x=n ^ is obtained after flipping x = m x=m x=m , is the right boundary of the rectangle, so the rectangular point weight is i q j p i^qj^p iqjp (note that it's flipped)

The sum of point weights in the trapezoid is f c , c − b − 1 , a , m − 1 f_{c,c-b-1,a,m-1} fc,c − b − 1,a,m − 1, then change: ( i , j ) → ( i + 1 , j ) → ( j , i + 1 ) (i,j) \rightarrow (i + 1, j) \rightarrow (j,i+1) (i,j)→(i+1,j)→(j,i+1)

Point weight change is i p j q → j p ( i + 1 ) q i^pj^q\rightarrow j^p(i+1)^q ipjq→jp(i+1)q

The binomial theorem is used to expand:
f a , b , c , n ( p , q ) = S q + ∑ t = 0 q ( q t ) f c , c − b − 1 , a , m − 1 ( t , p ) f_{a,b,c,n}(p,q)=S_q + \sum_{t=0}^q\dbinom{q}{t}f_{c,c-b-1,a,m-1}(t,p) fa,b,c,n​(p,q)=Sq​+t=0∑q​(tq​)fc,c−b−1,a,m−1​(t,p)

Problem calculation

In Case2 S t S_t St , is not easy to calculate. Consider finding the polynomial coefficient representation of the sum of powers of natural numbers

set up F q ( n ) = ∑ i = 0 n i q = ∑ i = 0 q + 1 c i n i F_q(n)=\sum_{i=0}^ni^q=\sum_{i=0}^{q+1}c_in^i Fq​(n)=∑i=0n​iq=∑i=0q+1​ci​ni ​

among ∑ i = 0 n i q \sum_{i=0}^ni^q ∑ i=0n ∑ iq ∑ should be a q + 1 q+1 Polynomial of power q+1

Lagrange interpolation method is used to calculate c i c_i ci, time complexity O ( q 3 ) O(q^3) O(q3)​
c i = ( x − x 0 ) ⋅ ⋅ ⋅ ( x − x i − 1 ) ( x − x i + 1 ⋅ ⋅ ⋅ ( x − x n ) ) ( x i − x 0 ) ⋅ ⋅ ⋅ ( x i − x i − 1 ) ( x i − x i + 1 ) ⋅ ⋅ ⋅ ( x i − x n ) c_i=\frac{(x-x_0)···(x-x_{i-1})(x-x_{i+1}···(x-x_n))}{(x_i-x_0)···(x_i-x_{i-1})(x_i-x_{i+1})···(x_i-x_n)} ci​=(xi​−x0​)⋅⋅⋅(xi​−xi−1​)(xi​−xi+1​)⋅⋅⋅(xi​−xn​)(x−x0​)⋅⋅⋅(x−xi−1​)(x−xi+1​⋅⋅⋅(x−xn​))​

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int mod = 998244353;

int norm(int x)
{
    if (x < 0)
    {
        x += mod;
    }
    if (x >= mod)
    {
        x -= mod;
    }
    return x;
}

template <class T>
T power(T a, int b)
{
    T res = 1;
    for (; b; b /= 2, a *= a)
    {
        if (b % 2)
        {
            res *= a;
        }
    }
    return res;
}

struct mint
{
    int x;
    mint(int x = 0) : x(norm(x)) {}
    int val() const
    {
        return x;
    }
    mint operator-() const
    {
        return mint(norm(mod - x));
    }
    mint inv() const
    {
        assert(x != 0);
        return power(*this, mod - 2);
    }
    mint &operator*=(const mint &rhs)
    {
        x = ll(x) * rhs.x % mod;
        return *this;
    }
    mint &operator+=(const mint &rhs)
    {
        x = norm(x + rhs.x);
        return *this;
    }
    mint &operator-=(const mint &rhs)
    {
        x = norm(x - rhs.x);
        return *this;
    }
    mint &operator/=(const mint &rhs)
    {
        return *this *= rhs.inv();
    }
    friend mint operator*(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res *= rhs;
        return res;
    }
    friend mint operator+(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res += rhs;
        return res;
    }
    friend mint operator-(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res -= rhs;
        return res;
    }
    friend mint operator/(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res /= rhs;
        return res;
    }
};

vector<mint> Lagrange(vector<mint> x, vector<mint> y)
{
    int n = x.size();
    vector<mint> f(n + 1, 0);
    vector<mint> g(n + 1, 0);
    vector<mint> conf(n + 1, 0);
    f[0] = 1;
    for (int i = 0; i < n; i += 1)
    {
        for (int j = i; j >= 0; j -= 1)
        {
            f[j + 1] += f[j];
            f[j] = -f[j] * x[i];
        }
    }
    for (int i = 0; i < n; i += 1)
    {
        for (int j = n - 1; j >= 0; j -= 1)
        {
            g[j] = f[j + 1] + g[j + 1] * x[i];
        }
        mint cur = 1;
        for (int j = 0; j < n; j += 1)
        {
            if (i != j)
                cur *= x[i] - x[j];
        }
        cur = 1 / cur;
        for (int j = 0; j <= n; j += 1)
        {
            g[j] *= cur;
            conf[j] += g[j] * y[i];
        }
    }
    return conf;
}

namespace EulerLike
{
    int has[220][120][120];
    ll val[220][120][120];
    ll C[120][120];
    ll A[120][120];
    ll inv[120], ber[120];

    // get Bernoulli numbers
    void getber()
    {
        int i, j;
        inv[1] = 1;
        for (i = 2; i < 110; i++)
            inv[i] = mod - 1ll * mod / i * inv[mod % i] % mod;
        ber[0] = 1;
        for (i = 0; i < 110; i++)
        {
            for (j = 0; j < i; j++)
            {
                ber[i] += mod - 1ll * C[i][j] * ber[j] % mod * inv[i - j + 1] % mod;
                ber[i] %= mod;
                if (ber[i] < 0)
                    ber[i] += mod;
            }
        }
        ber[1] = inv[2];
    }

    void init()
    {
        C[0][0] = 1;
        for (int i = 1; i <= 110; i++)
        {
            C[i][0] = 1;
            for (int j = 1; j <= 110; j++)
            {
                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
            }
        }
        getber();
        for (int i = 0; i <= 105; i++)
        {
            for (int j = 1; j <= i + 1; j++)
            {
                A[i][j] = C[i + 1][j] * inv[i + 1] % mod * ber[i + 1 - j] % mod;
            }
        }
    }

    void add(ll &a, ll b)
    {
        a += b;
        a %= mod;
    }

    ll qpow(ll f, int x)
    {
        ll s = 1;
        while (x)
        {
            if (x % 2 == 1)
                s = s * f % mod;
            f = f * f % mod;
            x = x / 2;
        }
        return s % mod;
    }

    //calculate sum (i=0~n) i^p
    ll S(ll n, ll p)
    {
        ll i, ret = 0;
        for (i = p + 1; i >= 1; i--)
        {
            ret = (ret * n + A[p][i]) % mod;
            //printf ( "S %lld %lld\n" , ret , A[p][i] );
        }
        ret = ret * n % mod;
        return ret;
    }

    ll F(ll n, ll a, ll b, ll c, int p, int q, int d = 0)
    {
        if (n < 0)
            return 0;
        if (has[d][p][q])
            return val[d][p][q];
        has[d][p][q] = true;
        ll &ret = val[d++][p][q] = 0;
        if (!q)
            ret = S(n, p) + (!p);
        else if (!a)
        {
            ret = qpow(b / c, q) * (S(n, p) + (!p)) % mod;
        }
        else if (a >= c)
        {
            ll m = a / c, r = a % c, mp = 1;
            for (int j = 0; j <= q; j++, mp = mp * m % mod)
                add(ret, C[q][j] * mp % mod * F(n, r, b, c, p + j, q - j, d) % mod);
        }
        else if (b >= c)
        {
            ll m = b / c, r = b % c, mp = 1;
            for (int j = 0; j <= q; j++, mp = mp * m % mod)
                add(ret, C[q][j] * mp % mod * F(n, a, r, c, p, q - j, d) % mod);
        }
        else
        {
            ll m = (a * n + b) / c;
            for (int k = 0; k < q; k++)
            {
                ll s = 0;
                for (int i = 1; i <= p + 1; i++)
                {
                    add(s, A[p][i] * F(m - 1, c, c - b - 1, a, k, i, d) % mod);
                }
                add(ret, C[q][k] * s % mod);
            }
            ret = (qpow(m, q) * S(n, p) + mod - ret) % mod;
        }
        return ret;
    }
};

int a, b, c, p, q, n;

int main()
{
    EulerLike::init();
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> a >> b >> c >> p >> q >> n;

    vector<mint> x, y;
    mint sum = 0;
    for (int i = 1; i <= q + 2; i += 1)
    {
        sum += power(mint(i), q);
        x.emplace_back(i);
        y.emplace_back(sum);
    }
    auto conf = Lagrange(x, y);

    mint ans = 0;
    for (int i = 0; i < conf.size(); i++)
    {
        //memset ( has , 0 , sizeof (has) );
        //memset ( val , 0 , sizeof (val) );
        ans += conf[i] * EulerLike::F(n, a, b, c, p, i);
    }
    //printf ( "%d\n" , mx );
    printf("%d\n", ans.val());
    return 0;
}

obtain S t = ∑ i = 0 n i p ∑ i = 0 q + 1 c t ( k i ) t = ∑ i = 0 q + 1 c t k t F p + t ( n ) S_t=\sum_{i=0}^ni^p\sum_{i=0}^{q+1}c_t(ki)^t=\sum_{i=0}^{q+1}c_tk^tF_{p+t}(n) St​=∑i=0n​ip∑i=0q+1​ct​(ki)t=∑i=0q+1​ct​ktFp+t​(n)

The above formula becomes the sum of q q q. relevant formula, F F F can be calculated quickly, with time complexity O ( q 2 ) O(q^2) O(q2)

Total time complexity O ( ( p + q ) 3 l o g max ⁡ ( a , c ) O((p+q)^3log\max(a,c) O((p+q)3logmax(a,c)

code

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int mod = 998244353;

int norm(int x)
{
    if (x < 0)
    {
        x += mod;
    }
    if (x >= mod)
    {
        x -= mod;
    }
    return x;
}

template <class T>
T power(T a, int b)
{
    T res = 1;
    for (; b; b /= 2, a *= a)
    {
        if (b % 2)
        {
            res *= a;
        }
    }
    return res;
}

struct mint
{
    int x;
    mint(int x = 0) : x(norm(x)) {}
    int val() const
    {
        return x;
    }
    mint operator-() const
    {
        return mint(norm(mod - x));
    }
    mint inv() const
    {
        assert(x != 0);
        return power(*this, mod - 2);
    }
    mint &operator*=(const mint &rhs)
    {
        x = ll(x) * rhs.x % mod;
        return *this;
    }
    mint &operator+=(const mint &rhs)
    {
        x = norm(x + rhs.x);
        return *this;
    }
    mint &operator-=(const mint &rhs)
    {
        x = norm(x - rhs.x);
        return *this;
    }
    mint &operator/=(const mint &rhs)
    {
        return *this *= rhs.inv();
    }
    friend mint operator*(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res *= rhs;
        return res;
    }
    friend mint operator+(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res += rhs;
        return res;
    }
    friend mint operator-(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res -= rhs;
        return res;
    }
    friend mint operator/(const mint &lhs, const mint &rhs)
    {
        mint res = lhs;
        res /= rhs;
        return res;
    }
};

vector<mint> Lagrange(vector<mint> x, vector<mint> y)
{
    int n = x.size();
    vector<mint> f(n + 1, 0);
    vector<mint> g(n + 1, 0);
    vector<mint> conf(n + 1, 0);
    f[0] = 1;
    for (int i = 0; i < n; i += 1)
    {
        for (int j = i; j >= 0; j -= 1)
        {
            f[j + 1] += f[j];
            f[j] = -f[j] * x[i];
        }
    }
    for (int i = 0; i < n; i += 1)
    {
        for (int j = n - 1; j >= 0; j -= 1)
        {
            g[j] = f[j + 1] + g[j + 1] * x[i];
        }
        mint cur = 1;
        for (int j = 0; j < n; j += 1)
        {
            if (i != j)
                cur *= x[i] - x[j];
        }
        cur = 1 / cur;
        for (int j = 0; j <= n; j += 1)
        {
            g[j] *= cur;
            conf[j] += g[j] * y[i];
        }
    }
    return conf;
}

namespace EulerLike
{
    int has[220][120][120];
    ll val[220][120][120];
    ll C[120][120];
    ll A[120][120];
    ll inv[120], ber[120];

    // get Bernoulli numbers
    void getber()
    {
        int i, j;
        inv[1] = 1;
        for (i = 2; i < 110; i++)
            inv[i] = mod - 1ll * mod / i * inv[mod % i] % mod;
        ber[0] = 1;
        for (i = 0; i < 110; i++)
        {
            for (j = 0; j < i; j++)
            {
                ber[i] += mod - 1ll * C[i][j] * ber[j] % mod * inv[i - j + 1] % mod;
                ber[i] %= mod;
                if (ber[i] < 0)
                    ber[i] += mod;
            }
        }
        ber[1] = inv[2];
    }

    void init()
    {
        C[0][0] = 1;
        for (int i = 1; i <= 110; i++)
        {
            C[i][0] = 1;
            for (int j = 1; j <= 110; j++)
            {
                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
            }
        }
        getber();
        for (int i = 0; i <= 105; i++)
        {
            for (int j = 1; j <= i + 1; j++)
            {
                A[i][j] = C[i + 1][j] * inv[i + 1] % mod * ber[i + 1 - j] % mod;
            }
        }
    }

    void add(ll &a, ll b)
    {
        a += b;
        a %= mod;
    }

    ll qpow(ll f, int x)
    {
        ll s = 1;
        while (x)
        {
            if (x % 2 == 1)
                s = s * f % mod;
            f = f * f % mod;
            x = x / 2;
        }
        return s % mod;
    }

    //calculate sum (i=0~n) i^p
    ll S(ll n, ll p)
    {
        ll i, ret = 0;
        for (i = p + 1; i >= 1; i--)
        {
            ret = (ret * n + A[p][i]) % mod;
            //printf ( "S %lld %lld\n" , ret , A[p][i] );
        }
        ret = ret * n % mod;
        return ret;
    }

    ll F(ll n, ll a, ll b, ll c, int p, int q, int d = 0)
    {
        if (n < 0)
            return 0;
        // memory
        if (has[d][p][q])
            return val[d][p][q];
        has[d][p][q] = true;
        ll &ret = val[d++][p][q] = 0;
        if (!q)
            ret = S(n, p) + (!p);
        else if (!a)
        {
            ret = qpow(b / c, q) * (S(n, p) + (!p)) % mod;
        }
        // Case 1
        else if (b >= c)
        {
            // mp represent m mod p
            ll m = b / c, r = b % c, mp = 1;
            for (int j = 0; j <= q; j++, mp = mp * m % mod)
                add(ret, C[q][j] * mp % mod * F(n, a, r, c, p, q - j, d) % mod);
        }
        // Case 2
        else if (a >= c)
        {
            ll m = a / c, r = a % c, mp = 1;
            for (int j = 0; j <= q; j++, mp = mp * m % mod)
                add(ret, C[q][j] * mp % mod * F(n, r, b, c, p + j, q - j, d) % mod);
        }
        // Case 3
        else
        {
            ll m = (a * n + b) / c;
            for (int k = 0; k < q; k++)
            {
                ll s = 0;
                for (int i = 1; i <= p + 1; i++)
                {
                    add(s, A[p][i] * F(m - 1, c, c - b - 1, a, k, i, d) % mod);
                }
                add(ret, C[q][k] * s % mod);
            }
            ret = (qpow(m, q) * S(n, p) + mod - ret) % mod;
        }
        return ret;
    }
};

int a, b, c, p, q, n;

int main()
{
    EulerLike::init();
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> a >> b >> c >> p >> q >> n;

    vector<mint> x, y;
    mint sum = 0;
    for (int i = 1; i <= q + 2; i += 1)
    {
        sum += power(mint(i), q);
        x.emplace_back(i);
        y.emplace_back(sum);
    }
    auto conf = Lagrange(x, y);

    mint ans = 0;
    for (int i = 0; i < conf.size(); i++)
    {
        //memset ( has , 0 , sizeof (has) );
        //memset ( val , 0 , sizeof (val) );
        ans += conf[i] * EulerLike::F(n, a, b, c, p, i);
    }
    //printf ( "%d\n" , mx );
    printf("%d\n", ans.val());
    return 0;
}
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <cassert>
#include <ctime>
#include <bitset>
typedef long long ll;
using namespace std;
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pil pair<int, ll>
#define pli pair<ll, int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define N 105
int fac[N << 1], inv[N << 1];
const int mod = 998244353;
ll qp(ll a, int p)
{
    ll ans = 1;
    for (; p; p >>= 1, a = a * a % mod)
        if (p & 1)
            ans = ans * a % mod;
    return ans;
}
int s[N << 1][N << 1];
int C(int n, int m)
{
    assert(n >= m);
    return 1LL * fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void init()
{
    int i, j, k, t;
    fac[0] = 1;
    for (i = 1; i < N; i++)
        fac[i] = 1LL * fac[i - 1] * i % mod;
    inv[N - 1] = qp(fac[N - 1], mod - 2);
    for (i = N - 2; i >= 0; i--)
        inv[i] = 1LL * inv[i + 1] * (i + 1) % mod;
    // S(n,k) = \sum_{i=1}^{n} i^k = \sum_{i=0}^k s(k,i) n^i
    s[0][1] = 1; // S(n,0) = n  WARN: S(0,0) = 1
    for (k = 1; k + 1 < N << 1; k++)
    {
        int invk = qp(k + 1, mod - 2);
        for (i = 0; i <= k + 1; i++)
        {
            for (t = 0; t < k; t++)
                s[k][i] = (s[k][i] - 1LL * C(k + 1, t) * s[t][i]) % mod;
            if (i)
                s[k][i] += C(k + 1, i);
            s[k][i] = 1LL * s[k][i] * invk % mod;
        }
    }
}
int getS(int n, int k)
{
    assert(k < N << 1);
    if (k == 0)
        return n + 1; // 0^0 = 1
    int i, res = 0;
    for (i = k + 1; i >= 0; i--)
        res = (1LL * res * n + s[k][i]) % mod;
    return (res + mod) % mod;
}
int queryS(int l, int r, int k)
{
    ll res = getS(r, k);
    if (l)
        res -= getS(l - 1, k);
    return (res % mod + mod) % mod;
}
struct T
{
    int a[N][N];
} emp;
int pwtmp[N];
int mx;
T calc(int a, int b, int c, int n)
{
    if (n < 0)
        return emp;
    int p, q, t;
    T res;
    if (a == 0)
    {
        for (p = 0; p < mx; p++)
        {
            for (q = 0; q < mx - p; q++)
            {
                res.a[p][q] = 1LL * queryS(0, n, p) * queryS(1, b / c, q) % mod;
            }
        }
    }
    else if (b >= c)
    {
        int k = b / c;
        T rem = calc(a, b % c, c, n);
        pwtmp[0] = 1;
        for (int i = 1; i < mx; i++)
            pwtmp[i] = 1LL * pwtmp[i - 1] * k % mod;
        for (p = 0; p < mx; p++)
        {
            for (q = 0; q < mx - p; q++)
            {
                res.a[p][q] = 1LL * queryS(0, n, p) * queryS(1, k, q) % mod;
                for (t = 0; t <= q; t++)
                    (res.a[p][q] += 1LL * C(q, t) * pwtmp[q - t] % mod * rem.a[p][t] % mod) %= mod;
            }
        }
    }
    else if (a >= c)
    {
        int k = a / c;
        T rem = calc(a % c, b, c, n);
        pwtmp[0] = 1;
        for (int i = 1; i < mx; i++)
            pwtmp[i] = 1LL * pwtmp[i - 1] * k % mod;
        for (p = 0; p < mx; p++)
        {
            for (q = 0; q < mx - p; q++)
            {
                // \sum_{i=0}^n\sum_{j=1}^{ki} i^p j^q
                ll tmp = 0;
                for (t = 0; t <= q + 1 && t < N; t++)
                    (tmp += 1LL * s[q][t] * pwtmp[t] % mod * queryS(0, n, p + t)) %= mod;
                res.a[p][q] = tmp;
                for (t = 0; t <= q && p + q - t < N; t++)
                    (res.a[p][q] += 1LL * C(q, t) * pwtmp[q - t] % mod * rem.a[p + q - t][t] % mod) %= mod;
            }
        }
    }
    else
    {
        int k = (1LL * a * n + b) / c % mod; // can mod!
        T rem = calc(c, c - b - 1, a, k - 1);
        for (p = 0; p < mx; p++)
        {
            for (q = 0; q < mx - p; q++)
            {
                res.a[p][q] = 1LL * queryS(1, n, p) * queryS(1, k, q) % mod; // TODO
                for (t = 0; t <= q; t++)
                    (res.a[p][q] -= 1LL * C(q, t) * rem.a[t][p] % mod) %= mod;
            }
        }
    }
    //	printf("res of %d %d %d %d:\n",a,b,c,n);
    //	for(int i=0;i<5;i++){
    //		for(int j=0;j<5;j++)printf("%d ",(res.a[i][j]+mod)%mod);
    //		puts("");
    //	}
    return res;
}
int main()
{
    int a, b, c, p, q, n;
    init();
    scanf("%d%d%d%d%d%d", &a, &b, &c, &p, &q, &n);
    mx = p + q + 3;
    T res = calc(a, b, c, n);
    printf("%d\n", (res.a[p][q] + mod) % mod);
    // 	printf("%lf",1.0*clock()/CLOCKS_PER_SEC);
    return 0;
}

Keywords: Math

Added by Cleanselol on Fri, 24 Dec 2021 12:38:27 +0200