Description

小 T 最近在学着买股票, 他得到内部消息: F 公司的股票将会疯涨. 股票每天的价格已知是 正整数, 并且由于客观上的原因, 最多只能为 \(n\). 在疯涨的 \(k\) 天中小 T 观察到: 除第一天 外每天的股价都比前一天高, 且高出的价格 (即当天的股价与前一天的股价之差) 不会超过 \(m\),\(m\) 为正整数. 并且这些参数满足 \(m(k - 1) \lt n\).

小 T 忘记了这 \(k\) 天每天的具体股价了, 他现在想知道这 \(k\) 天的股价有多少种可能.

Input

只有一行用空格隔开的四个数:\(n, k, m, p\). 对 \(p\) 的说明参见后面输出格式中对 \(p\) 的解释.

Output

仅包含一个数, 表示这 \(k\) 天的股价的可能种数对于 \(p\) 的模值.

Sample Input

7 3 2 997

Sample Output

16

Data Range

对于 20% 的数据, 满足:\(m, n, k, p \leq 20000\);

对于 100% 的数据, 满足:\(m, k, p \leq 10^9, n \leq 10^{18}\).

Explanation

神犇题解:http://www.cnblogs.com/jianglangcaijin/archive/2013/08/13/3254314.html

设相邻两项的差值为 \(a[i] = A[i+1] - A[i]\), 那么每一个这样的序列对答案的贡献为:

\[S = n - \sum_{i}^{k-1} a[i]\]

这样的序列 \(a\)\(m^{k-1}\) 种, 则:

\[ans = \sum_{a[1]=1}^{m} \sum_{a[2]=1}^{m} \cdots \sum_{a[k-1]=1}^{m} (n - a[1] - a[2] - \ldots - a[k-1])\\ = n \cdot m^{k-1} - \sum_{a[1]=1}^{m} \sum_{a[2]=1}^{m} \cdots \sum_{a[k-1]=1}^{m} (a[1] + a[2] + \ldots + a[k-1])\\ = n \cdot m^{k-1} - \frac{m(m+1)}{2} \cdot m^{k-1} \cdot (k-1)\]

后面那一项是有 \(m^{k-1}\) 个数列, 每个数列有 \(k-1\) 个数, 则一共有 \(m^{k-1} \cdot (k-1)\) 个数,\(m\) 个数每个数均出现相等次数, 则每个数均出现 \(m^{k-2} \cdot (k-1)\) 次,\(m\) 个数的和为 $, 则总和为:

\[\frac{m(m+1)}{2} \cdot m^{k-1} \cdot (k-1)\]

照着 \(ans\) 推一遍结果基本就出来了.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef long long lli;
/* const */ lli modr = 1000000007;

lli qpow(lli a, lli b)
{
    lli res = 1;
    for (; b > 0; b >>= 1, a = a*a % modr)
        if (b & 1)
            res = res * a % modr;
    return res;
}

lli n, m, k;

int main(int argc, char** argv)
{
    scanf("%lld%lld%lld%lld", &n, &k, &m, &modr);
    lli res = n % modr * qpow(m, k-1) % modr
        - m * (m+1) / 2 % modr * qpow(m, k-2) % modr * (k-1) % modr;
    res = (res % modr + modr) % modr;
    printf("%lld\n", res);
    return 0;
}