[HNOI2013]数列
[HNOI2013]数列
直接推很帅,可惜我不会。
不难发现,若知道第一天和最后一天的差值为\(d\),则只需算出中间\(k-1\)天增长为\(d\)的方案数即可,假设增长为\(d\)的方案数为\(h_d\),那么答案就是
\[\sum_{i=d}^n (n-d) f_d=n\sum_d f_d + \sum_d d f_d
\]
这个\(f_d\)用\(\text{GF}\)套路很好表示,设
\[\begin{aligned}
F(x) = \sum_{1 \leq k \leq m} x^k
\end{aligned}
\]
那么考虑
\[G(x) = (F(x))^{k - 1}
\]
答案就是
\[n\sum_k [x^k]G(x) + \sum_k [x^k]G'(x)
\]
题目给了\(m(k-1) < n\),那么直接代\(x=1\)算就行了
那么答案就是
\[nm^{k-1} - \frac{m(m + 1)}{2} (k - 1) m^{k - 2}
\]
直接算就行了。
点我看代码|ू・ω・` )
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; int f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
if(f) x = ~x + 1;
}
LL n, k, m, P;
LL fpow(LL x, int pnt) {
LL res = 1;
for(; pnt; pnt >>= 1, x = x * x % P) if(pnt & 1) res = res * x % P;
return res;
}
int main() {
read(n), read(k), read(m), read(P);
printf("%lld\n",(n % P * fpow(m, k - 1) % P - fpow(m, k - 2) % P * ((m + 1) * m / 2 % P) % P * (k - 1 + P) % P + P) % P);
}