首页 > 其他分享 >洛谷P5907 数列求和加强版 / SPOJ MOON4

洛谷P5907 数列求和加强版 / SPOJ MOON4

时间:2024-02-03 14:00:12浏览次数:18  
标签:frac int sum ret MOON4 SPOJ Bmatrix P5907 underline

题面描述

\[\sum_{i=1}^ni^ka^i \]

对 \(998244353\) 取模的结果。

\(O(k)\)做法

为了推导方便,下令 \(p = a^{-1}\)。即求

\[\sum_{i=1}^n\frac{i^k}{p^i} \]

我们裂项,即尝试寻找多项式 \(f(x)\),使得

\[\frac{x^k}{p^x} = \frac{f(x)}{p^{x-1}} - \frac{f(x+1)}{p^x} \]

\[x^k = pf(x) - f(x+1)(*) \]

答案将是 \(f(1) - \frac{f(n+1)}{p^n}\)。

显然 \(\deg f = k\)。

这样临项点值的差,由于恒等式 \((x + 1)^{\underline{n}}- x ^ {\underline{n}} = nx^{\underline{n-1}}\),可以考虑展开成下降幂来推导。具体地,设 \(f(x) = \sum\limits_{i = 0}^n c_ix^{\underline{i}}\),则可以展开 \((*)\) 式:

\[ \begin{aligned} x^k = \sum^k_{i = 0}\begin{Bmatrix}k \\ i\end{Bmatrix}x^{\underline{i}} &= \sum_{i = 0}^k pc_ix^{\underline{i}} - \sum_{i = 0}^k c_i(x + 1)^{\underline{i}} \\ &= \sum_{i = 0}^k(p-1)c_ix^{\underline{i}} - \sum_{i=1}^kic_ix^{\underline{i-1}} \\ &= (p-1)c_kx^{\underline{k}}+\sum_{i=0}^{k-1}((p-1)c_i-(i+1)c_{i+1})x^{\underline{i}} \end{aligned}\]

对比系数能够得到:

\[(p - 1)c_k = \begin{Bmatrix}k \\ k\end{Bmatrix} = 1 \]

\(i = 0, 1...,k-1\):

\[(p - 1)c_i - (i+1)c_{i+1} = \begin{Bmatrix}k \\ i\end{Bmatrix} \]

求一行斯特林数是 \(O(k \log k)\)的,需要进一步优化。

直接求每一项系数也许有些困难,但是这里有一个取巧的办法:
如果我们知道 \(f(0)\),那么通过\((*)\)式,可以递推出 \(f(1), ...f(k)\),那么就可以利用这 \(k+1\) 个点值进行线性拉格朗日插值,避开了这个难处。

而 \(f(0)=c_0\),因此下面我们只需要求出 \(c_0\) 即可。省略这一步过程,我们恰好可以将这个系数的递推式求出来,即

\[c_0 = \frac 1 {p - 1}\sum_{i = 0}^k\begin{Bmatrix}k \\ i\end{Bmatrix} \frac{i!}{(p-1)^i} \]

这个式子是可以 \(O(k)\) 求解的,参见 EI 的 Binomial Sum。由于我也是第一次学这个所以下面还是写一下过程。

下面令 \(t = (p-1)^{-1}\) ,求

\[\sum_{i = 0}^k\begin{Bmatrix}k \\ i\end{Bmatrix} t^i i! \]

写成生成函数就是

\[\begin{aligned} \sum_{i = 0}^kt^i \begin{Bmatrix}k \\ i\end{Bmatrix} i! &= \sum_{i = 0}^k t^i \left[\frac{z^k}{k!}\right](\exp z-1)^i \\ &= \left[\frac{z^k}{k!}\right]\sum_{i=0}^k (t(\exp z - 1))^i \\ &= \left[\frac{z^k}{k!}\right] \frac 1 {1 - t(\exp z - 1)} \end{aligned} \]

令 \(u = \exp z\),对于 \(z\) 来说,这本应是一个无穷级数,但利用 \(\exp z - 1\) 没有常数项的性质,我们可以将对于 \(u\) 的求和上限限制在 \(k\) 处(截断),之后的项都不会有贡献。因此就是求

\[\left[\frac{z^k}{k!}\right] \frac {1 - (t(\exp z - 1))^{k+1}} {1 - t(\exp z - 1)} \]

那么 GF 写作:

\[G(u) = \frac {1 - (t(u-1))^{k+1}}{1-t(u-1)} \]

这是一个关于 \(u\) 的有理分式,将分母移到一边就可以 \(O(k)\) 求出 \(u^i\) 处系数,然后就做完了。退役OIer不想省略下面的细节,继续推导。我们设 \(G(u) = \sum\limits_{i\ge0}g_iu^i\),那么

\[g_0 = G(0) = \frac{1+t^{k+1}(-1)^k}{1+t} \]

\[(1+t-tu)G = 1-t^{k+1}(u-1)^{k+1} \]

提取系数就是

\[(1+t)g_i-tg_{i-1}=t^{k+1}\binom{k+1}{i}(-1)^{k-i} \]

最后,我们得到了,

\[\begin{aligned} c_0 &= t \left[\frac{z^k}{k!}\right] \sum_{i=0}^k g_i \exp iz \\ &= t\sum_{i=0}^k g_i i^k \end{aligned}\]

这道题几乎做完了。剩下的就是特判 \(a=p=1\) 的情况,此时问题退化为自然数幂和,可以直接线性拉格朗日插值。

代码(代码中,使用 \(m\) 代替了 \(k\)):

#include <cstdio>
#define ll long long
const int M = 1e7, mod = 998244353;
inline int mul(int a, int b) {return (ll)a * b % mod;}
inline int add(int a, int b) {int ret = a + b; return ret >= mod ? ret - mod : ret;}
inline int minus(int a, int b) {int ret = a - b; return ret < 0 ? ret + mod : ret;}
inline int qpow(int a, int b) {
    int ret = 1;
    for(; b; b >>= 1, a = mul(a, a))
        if(b & 1)   ret = mul(ret, a);
    return ret;
}
int f[M + 5], g[M + 5], p, n, m, ip, ip1;
int fac[M + 5], invf[M + 5];
int pre, suf[M + 5];
int cnt, v[M + 5], pr[M >> 2], pwm[M + 5];
inline int C(int m, int n) {return (ll)fac[m] * invf[n] % mod * invf[m - n] % mod;}
inline int pn1(int num, int p) {return p & 1 ? mod - num : num;}

int main() {
    scanf("%d%d%d", &n, &ip, &m);
    //initialization
    fac[0] = 1;
    p = qpow(ip, mod - 2);
    for(int i = 1; i <= m + 1; ++i) fac[i] = mul(fac[i - 1], i);
    invf[m + 1] = qpow(fac[m + 1], mod - 2);
    for(int i = m; i >= 0; --i) invf[i] = mul(invf[i + 1], i + 1);

    pwm[1] = 1;
    for(int i = 2; i <= m + 2; ++i) {
        if(!v[i]) v[i] = pr[++cnt] = i, pwm[i] = qpow(i, m);
        for(int j = 1; j <= cnt; ++j) {
            if(pr[j] > v[i] || i * pr[j] > m + 2)    break;
            v[i * pr[j]] = pr[j];
            pwm[i * pr[j]] = mul(pwm[i], pwm[pr[j]]);
        }
    }
    ip1 = qpow(p - 1, mod - 2);
    if(p ^ 1) {
	    //calulate g, f
	    int t1 = qpow(ip1 + 1, mod - 2), t2 = qpow(ip1, m + 1);
	    // t1 = 1/t + 1, t2 = t ^ {m + 1}
	    g[0] = mul(t1, 1 + pn1(t2, m));
	    for(int i = 1; i <= m; ++i) {
	        g[i] = mul(t1, mul(ip1, g[i - 1]) + mul(C(m + 1, i), pn1(t2, m - i)));
	        f[0] = add(f[0], mul(pwm[i], g[i]));
	    }
		f[0] = mul(ip1, f[0]);
	}
    if(p ^ 1)	for(int i = 1; i <= m; ++i)
        	f[i] = minus(mul(p, f[i - 1]), pwm[i - 1]);
	else for(int i = 1; i <= m + 1; ++i)
		f[i] = add(f[i - 1], pwm[i]);
       
    //prepare for lagruange interpolation
    if(p == 1)	--n, ++m;
    pre = n + 1, suf[m + 1] = 1;
//    for(int i = 1; i <= m; ++i) pre[i] = mul(pre[i - 1], (mod + n + 1 - i) % mod);
    for(int i = m; i >= 1; --i) suf[i] = mul(suf[i + 1], minus(n + 1, i));
    
    //calculate answer
    int Ans = mul(f[0], pn1(mul(suf[1], invf[m]), m));
    for(int i = 1; i <= m; ++i)
       Ans = add(Ans, pn1(mul(f[i], mul(mul(pre, suf[i + 1]), mul(invf[i], invf[m - i]))), m - i)),
    	pre = mul(pre, minus(n + 1, i));
    if(p ^ 1)	Ans = minus(f[1], mul(Ans, qpow(qpow(p, n), mod - 2)));
	
    printf("%d", Ans);
    return 0;
}

标签:frac,int,sum,ret,MOON4,SPOJ,Bmatrix,P5907,underline
From: https://www.cnblogs.com/Martin-MHT/p/18004601

相关文章

  • SPOJ1805 HISTOGRA - Largest Rectangle in a Histogram 题解
    LinkSPOJ1805HISTOGRA-LargestRectangleinaHistogramQuestion在一条水平线上有\(n\)个高为\(a_i\)的矩形,求包含于这些矩形的最大子矩形面积。Solution我们定义\(L_i\)表示有\(a_i\)这个高度的一根悬线,往左最多能平移到什么位置初始化显然,\(a_i=i\)考虑转移......
  • SPOJ Substrings 题解
    \(\text{SAM}\)入门好题。首先我们需要知道几个关于\(\text{SAM}\)的结论。结论1:题目中的\(f(x)\)单调下降。显然,对于长度为\(x\)的子串,其必存在一个\(x-1\)的后缀,这个后缀的\(\text{endpos}\)集合肯定包含子串的\(\text{endpos}\)集合,所以必有\(f(x-1)\le......
  • SPOJ4487(Splay树)
    题目:http://www.spoj.com/problems/GSS6/ 题意:给一个长度为n的数组,然后给出Q个4种操作,分别是:删除,插入,替换,查找指定区间连续最大和。#include<iostream>#include<string.h>#include<stdio.h>usingnamespacestd;constintN=200005;constintINF=1<<28;inta[N];......
  • SPOJ COT3 Combat on a tree
    简要题意给定一棵有根树,初始有黑点白点。两人交替操作,每次选择一个白点,将这个点到根路径上所有点染黑,选不了则输。求先手能否必胜;如果能,给出第一步可能的所有走法。数据范围:\(1\len\le10^5\)。题解小清新题。难度不配黑题。进行一次操作以后,这个点到根路径上所有点两侧的子......
  • SPOJ 1825 FTOUR2 - Free tour II (树上点分治)
    题目地址:SPOJ1825树分治的题果然除了模板题就是金牌题啊。。。这题是一道论文题,想了好长时间。。。。终于过了,,,,注意一个坑点,如果权值全部为负的话,是可以不选任意一条边的,这样权值为0。。。也就是说初始值要设为0。。。具体看漆子超的论文《分治算法在树的路径问题中的应用》......
  • SPOJ 705 New Distinct Substrings (后缀数组)
    后缀数组模板题。由于height数组是指与排名上一个的公共前缀,所以重复的个数是height[i]个,考虑当前这个字母所构成的子串的贡献即为n-sa[i]-height[i],然后累加即可。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm......
  • SPOJ 375 QTREE系列-Query on a tree (树链剖分)
    题目地址:SPOJ375树链剖分第一发!果然是个貌似很高级的数据结构,其实就是把树的边从树形结构转化成了线性结构,从而可以用线段树或树状数组之类的数据结构进行快速维护。从而将时间缩到n*log(2*n).这题用的线段树维护的。代码如下:#include<iostream>#include<string.h......
  • SPOJ Query On A Tree IV 题解
    SPOJQueryOnATreeIV题解一个边分治套线段树套堆的题目比较难写但是有不小的启发思路来源和代码都抄自[SPOJ-QTREE4]QUERYONATREEIV题解|KSKUN'sBlog简......
  • [SPOJ] DIVCNT2 - Counting Divisors (square) (平方的约数个数前缀和 容斥 卡常)
    题目vjudgeURL:​​CountingDivisors(square)​​​Letbethenumberofpositivedivisorsof.Forexample,,and.LetGiven,find.InputFirstlinecontains......
  • SPOJ375--Query on a tree(树链剖分)
    Description:Youaregivenatree(anacyclicundirectedconnectedgraph)with N nodes,andedgesnumbered1,2,3...N-1.Wewillaskyoutoperfromsomeins......