51NOD 序列求和 V5题解

来源:互联网 发布:乃木坂网络直播电视剧 编辑:程序博客网 时间:2024/05/17 03:40

  被数论くん搞得头大的本宝宝来写一发数论题~
  51NOD 序列求和 V5
  若R0 ,那么显然答案就为0.
  接下来,我们用符号f k (n) 代表我们所要求的值。首先我们要预处理f k (1),,f k (k+1) 的值,由于x k  是一个完全积性函数,利用线性筛,这一预处理可以很容易在O(k) 的时间内完成。
  若R1 ,则原问题转化为求 n i=1 i k  的值,我们知道,这时f k (n) 是关于n k+1 次多项式。同时,我们也知道,nk+1 时,每一个C i n  都是关于n i 次多项式,并且它们线性无关,而nk 时,可以O(1) 直接查询。对于nk+1 的情况,我们用C 0 n ,,C k+1 n  k+2 个数来线性表出f k (n) ,设f k (n)= k+1 i=0 C i n a i  ,根据二项式反演,有a n = n i=0 (1) ni C i n f k (i) 
  这里先写一个引理: k i=0 (1) i C i n =(1) k C k n1  ,这个很好证我就不写了。
  将a n  代回原式得:

f k (n) = i=0 k+1 C i n  j=0 i (1) ij C j i f k (j)= i=0 k+1 f k (i) j=i k+1 (1) ji C j n C i j = i=0 k+1 f k (i)C i n  j=i k+1 (1) ji C ji ni = i=0 k+1 f k (i)C i n  j=0 ki+1 (1) j C j ni = i=0 k+1 (1) ki+1 C i n C ki+1 ni1 = i=0 k+1  0jk+1,ji nji!(ki+1)!   

  这样,分子和分母的部分都可以预处理出来,复杂度O(k) 
  若R≢1 ,有:

(R1)f k (n)f k (n) =(R1) i=1 n i k R i = i=1 n i k R i+1  i=1 n i k R i = i=1 n+1 (i1) k R i  i=1 n i k R i =n k R n+1  i=1 n  j=0 k1 (1) kj1 C j k i j R i =n k R n+1  j=0 k1 (1) kj+1 C j k f j (n)=n k R n+1  k1 j=0 (1) kj+1 C j k f j (n)R1   

  下面我们证明一个结论,对f i (n),0ik,F i (n)Q i [x] ,有f i (n)=R n+1 F i (n)RF i (0) 

iif k (n) =0,()=k0,,k1=n k R n+1  k1 j=0 (1) kj+1 C j k f j (n)R1 =n k R n+1  k1 j=0 (1) kj+1 C j k [R n+1 F j (n)RF j (0)]R1 =R n+1 [n k  k1 j=0 (1) kj+1 C k j F j (n)]+R[ k1 j=0 (1) kj+1 C j k F j (0)]R1 F k (n)=n k  j=0 k1 (1) kj+1 C k j F j (n)  

  我们再来证明一个引理:对0mk, k i=0 (1) i C i k C m i =0 

 i=0 k (1) i C i k C m i  = i=0 k (1) i C m k C im km =C m k  i=0 km (1) i+m C i km =C m k (1) m (11) (km) =0  

  在上一部分的讨论中,我们已经知道,作为一个k 次多项式,F k (n) 可以表示为C 0 n ,,C k n  的线性组合。设F k (n)= k i=0 C i n a i  ,则
 i=0 k (1) i C i k F k (n) = i=0 k (1) i C i k  j=0 k C j i a j = j=0 k  i=0 k (1) i C i k C j i a j = j=0 k 0=0  

  我们又有:
(n+1) k R n+1 F k (n+1) =f k (n+1)f k (n)=R n+2 F k (n+1)R n+1 +RF k (0)=(n+1) k +F k (n)R   

  通过上面两个等式,我们就可以通过解一个一元一次方程来得到F k (0),,F k (k) 的值,之后我们用拉格朗日插值公式就可以O(k) 地得到F k (n) 的值,再代回原式,这道题就解决了。

#include<bits/stdc++.h>#define ll long longconst 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;}
0 0
原创粉丝点击