[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);
}
posted @ 2022-08-04 22:08  DCH233  阅读(32)  评论(0)    收藏  举报