思路
注意到:
⌊ki⌋=ki−imodk
那么我们有:
原式=i=0∑n(in)×pi×ki−imodk=k1i=0∑n(in)pi(i−imodk)=k1(i=0∑n(in)pii−i=0∑n(in)pi(imodk))
令 a=∑i=0n(in)pii,b=∑i=0n(in)pi(imodk),分别考虑计算两部分.
-
对于 a,注意到 (in)=(i−1n−1)in,我们有:
a=ni=1∑n(i−1n−1)pi=npi=0∑n−1(in−1)pi=np(p+1)n−1
容易计算.
-
对于 b,考虑枚举 imodk 的值,然后单位根反演:
b=i=0∑n(in)pij=0∑k−1j[j≡i(modk)]=i=0∑n(in)pij=0∑k−1j[k∣i−j]=i=0∑n(in)pij=0∑k−1jk1r=0∑k−1wk(i−j)r=k1r=0∑k−1j=0∑k−1jwk−jri=0∑n(in)piwkir=k1r=0∑k−1(pwkr+1)nj=0∑k−1jwk−jr
发现后面那个 ∑ 是非常经典的求和!不妨设 f(x)=∑i=0k−1ixi,后面那个就是 f(wk−j).错位相减可得:
f(x)={2k(k−1)x−1kx=1otherwise
然后 b 就能够快速计算了.
总时间复杂度 O(klogn).
代码
#include <cstdio>
inline int rd() {
int x = 0, f = 1, c = getchar();
while (((c - '0') | ('9' - c)) < 0)
f = c != '-', c = getchar();
while (((c - '0') | ('9' - c)) > 0)
x = x * 10 + c - '0', c = getchar();
return f ? x : -x;
}
using i64 = long long;
const i64 P = 998244353;
const i64 G = 3;
i64 fpow(i64 b, i64 p) {
i64 res = 1;
for(; p; b = b * b % P, p >>= 1) {
if(p & 1) res = res * b % P;
}
return res;
}
i64 inv(i64 x) { return fpow(x, P - 2); }
i64 n, p, k;
i64 f(i64 x) {
if(x == 1) return k * (k - 1) % P * inv(2) % P;
return k * inv((x - 1 + P) % P) % P;
}
int main() {
n = rd(), p = rd(), k = rd();
i64 wk = fpow(G, (P - 1) / k), w = 1, a = 0;
for(int i = 0; i < k; i++, (w *= wk) %= P) {
(a += fpow((p * w % P + 1) % P, n) * f(inv(w)) % P) %= P;
}
i64 b = n * p % P * fpow(p + 1, n - 1) % P;
printf("%lld\n", (b - a * inv(k) % P + P) % P * inv(k) % P);
return 0;
}