被数论くん搞得头大的本宝宝来写一发数论题~
51NOD 序列求和 V5
若
R≡0
,那么显然答案就为0.
接下来,我们用符号
f k (n)
代表我们所要求的值。首先我们要预处理
f k (1),⋯,f k (k+1)
的值,由于
x k
是一个完全积性函数,利用线性筛,这一预处理可以很容易在
O(k)
的时间内完成。
若
R≡1
,则原问题转化为求
∑ n i=1 i k
的值,我们知道,这时
f k (n)
是关于
n
的
这里先写一个引理:
∑ k i=0 (−1) i C i n =(−1) k C k n−1
,这个很好证我就不写了。
将
a n
代回原式得:
这样,分子和分母的部分都可以预处理出来,复杂度
O(k)
。
若
R≢1
,有:
下面我们证明一个结论,对
∀f i (n),0≤i≤k,∃F i (n)∈Q i [x]
,有
f i (n)=R n+1 F i (n)−RF i (0)
。
我们再来证明一个引理:对 ∀0≤m≤k,∑ k i=0 (−1) i C i k C m i =0
在上一部分的讨论中,我们已经知道,作为一个 k 次多项式,
我们又有:
通过上面两个等式,我们就可以通过解一个一元一次方程来得到 F k (0),⋯,F k (k) 的值,之后我们用拉格朗日插值公式就可以 O(k) 地得到 F k (n) 的值,再代回原式,这道题就解决了。
#include<bits/stdc++.h>
#define ll long long
const int N = 200010;
const int moder = 985661441;
int power(int a, ll index){
int ans = 1;
while (index){
if (index & 1)
ans = 1ll * ans * a % moder;
a = 1ll * a * a % moder;
index >>= 1;
}
return ans;
}
int min[N], x[N], f[N], F[N], prefix[N], suffix[N], fac[N], inv[N], t, k;
ll n, r;
std::vector <int> prime;
void calc(){
prefix[0] = suffix[k + 1] = 1;
for (int i = 1; i <= k + 1; ++ i){
prefix[i] = 1ll * prefix[i - 1] * ((n - i + 1) % moder) % moder;
}
for (int i = k; i >= 0; -- i){
suffix[i] = 1ll * suffix[i + 1] * ((n - i - 1) % moder) % moder;
}
int ans = 0;
for(int i = 0; i <= k + 1; ++ i){
int now = 1ll * f[i] * inv[i] % moder * inv[k - i + 1] % moder;
now = 1ll * now * prefix[i] % moder * suffix[i] % moder;
if ((k - i + 1) & 1)
now = (moder - now) % moder;
ans = (ans + now) % moder;
}
printf("%d\n", ans);
}
void _calc(){
int inv_r = power(r, moder - 2);
int sum_a = 1, sum_b = 0;
prefix[0] = 1;
suffix[0] = 0;
for (int i = 1; i <= k + 1; ++ i){
prefix[i] = 1ll * prefix[i - 1] * inv_r % moder;
suffix[i] = 1ll * (suffix[i - 1] + x[i]) * inv_r % moder;
int coe = 1ll * fac[k + 1] % moder * inv[i] % moder * inv[k + 1 - i] % moder;
if (i & 1)
coe = (moder - coe) % moder;
sum_a = (sum_a + 1ll * coe * prefix[i]) % moder;
sum_b = (sum_b + 1ll * coe * suffix[i]) % moder;
}
int _x = 1ll * (moder - sum_b) * power(sum_a, moder - 2) % moder;
for (int i = 0; i <= k; ++ i)
F[i] = (1ll * prefix[i] * _x + suffix[i]) % moder;
prefix[0] = suffix[k] = 1;
for (int i = 1; i <= k; ++ i){
prefix[i] = 1ll * prefix[i - 1] * ((n - i + 1) % moder) % moder;
}
for (int i = k - 1; i >= 0; -- i){
suffix[i] = 1ll * suffix[i + 1] * ((n - i - 1) % moder) % moder;
}
int ans = 0;
for(int i = 0; i <= k; ++ i){
int now = 1ll * F[i] * inv[k - i] % moder * inv[i] % moder;
now = 1ll * now * prefix[i] % moder * suffix[i] % moder;
if ((k - i) & 1)
now = (moder - now) % moder;
ans = (ans + now) % moder;
}
ans = (1ll * ans * power(r, n) - F[0] + moder) % moder;
ans = 1ll * ans * r % moder;
printf("%d\n", ans);
}
int main(){
scanf("%d", &t);
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for (int i = 2; i < N; ++ i){
fac[i] = 1ll * i * fac[i - 1] % moder;
inv[i] = power(fac[i], moder - 2);
if (!min[i]){
min[i] = i;
prime.push_back(i);
}
for (int j = 0; j < prime.size() && prime[j] <= i && prime[j] * i < N; ++ j)
min[prime[j] * i] = prime[j];
}
while (t --){
scanf("%d%I64d%I64d", &k, &n, &r);
r %= moder;
if (r == 0){
puts("0\n");
continue;
}
x[1] = 1;
int now = r;
f[1] = r;
for (int i = 2; i < k + 10; ++ i){
now = 1ll * now * r % moder;
if (min[i] == i)
x[i] = power(i, k);
else
x[i] = 1ll * x[min[i]] * x[i / min[i]] % moder;
f[i] = (f[i - 1] + 1ll * x[i] * now) % moder;
}
if (n < 1ll * (k + 10)){
printf("%d\n", f[n]);
continue;
}
if (r == 1){
calc();
continue;
}
_calc();
}
return 0;
}