用户工具

站点工具


2020-2021:teams:legal_string:jxm2001:多项式_1

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:jxm2001:多项式_1 [2020/08/02 23:33]
jxm2001
2020-2021:teams:legal_string:jxm2001:多项式_1 [2020/08/03 22:45] (当前版本)
jxm2001
行 50: 行 50:
 以 $x_i=i$ 为例,则 $(1)$ 式化为 以 $x_i=i$ 为例,则 $(1)$ 式化为
  
-$$f(x)=\sum_{i=1}^n y_i\prod_{j\neq i}\frac {x-j}{i-j}=\sum_{i=1}^n (-1)^{n-i}y_i\frac {\prod_{j=1}^{i-1}(x-j)\prod_{j=i+1}^{n}(x-j)}{(i-1)!(n-1-i)!}$$+$$f(x)=\sum_{i=1}^n y_i\prod_{j\neq i}\frac {x-j}{i-j}=\sum_{i=1}^n (-1)^{n-i}y_i\frac {\prod_{j=1}^{i-1}(x-j)\prod_{j=i+1}^{n}(x-j)}{(i-1)!(n-i)!}$$
  
 分子部分考虑 $O(n)$ 预处理序列 $\{x-i\}$ 的前缀积和后缀积,分母部分考虑 $O(n)$ 预处理阶乘的逆。 分子部分考虑 $O(n)$ 预处理序列 $\{x-i\}$ 的前缀积和后缀积,分母部分考虑 $O(n)$ 预处理阶乘的逆。
 +
 +<code cpp>
 +int inv_frac[MAXN],​y[MAXN],​pre[MAXN],​suf[MAXN];​
 +int Lagrange(int x,int n){
 + pre[0]=suf[n+1]=1;​
 + _rep(i,​1,​n)pre[i]=1LL*pre[i-1]*(x-i)%Mod;​
 + for(int i=n;​i;​i--)suf[i]=1LL*suf[i+1]*(x-i)%Mod;​
 + int ans=0,sign;
 + _rep(i,​1,​n){
 + sign=((n-i)&​1)?​-1:​1;​
 + ans=(ans+1LL*sign*y[i]*pre[i-1]%Mod*suf[i+1]%Mod*inv_frac[i-1]%Mod*inv_frac[n-i])%Mod;​
 + }
 + return ans;
 +}
 +</​code>​
  
 === 重心拉格朗日插值法 === === 重心拉格朗日插值法 ===
行 83: 行 98:
 } }
 </​code>​ </​code>​
 +
 +====  算法练习 ====
 +
 +=== 习题一 ===
 +
 +[[https://​www.luogu.com.cn/​problem/​P5437|洛谷p5437]]
 +
 +=== 题意 ===
 +
 +给定一个完全图,完全图中节点编号为 $1\sim n$。$i,j$ 节点间连一条边权为 $(i+j)^k$ 的边。
 +
 +随机选取 $n-1$ 条边得到一棵生成树,问生成树的边权和的期望值。
 +
 +=== 题解 ===
 +
 +发现每条边地位都是等价的,于是每条边出现在生成树的概率为 $\frac{2(n-1)}{n(n-1)}=\frac 2n$。
 +
 +于是不难得到答案为 $\frac 2n\sum_{i=1}^{n-1}\sum_{j=i+1}^n (i+j)^k$,记 $f(n)=\sum_{i=1}^{n-1}\sum_{j=i+1}^n (i+j)^k$,考虑如何快速求出 $f(n)$。
 +
 +$$f(n)-f(n-1)=\sum_{i=1}^{n-1}\sum_{j=i+1}^n (i+j)^k-\sum_{i=1}^{n-2}\sum_{j=i+1}^{n-1} (i+j)^k=(2n-1)^k+\sum_{i=1}^{n-2}(i+n)=\sum_{i=n+1}^{2n-1}i^k$$
 +
 +于是有 ​
 +
 +$$f(n)=
 +\begin{cases}
 +0, & n=1  \\
 +\sum_{i=2}^n\sum_{j=i+1}^{2i-1}j^k,​ & n\gt 1
 +\end{cases}
 +$$
 +
 +易知 $\sum_{j=i+1}^{2i-1}j^k$ 是 $k+1$ 次多项式,于是 $\sum_{i=2}^n\sum_{j=i+1}^{2i-1}j^k$ 是 $k+2$ 次多项式。
 +
 +线性筛预处理 $1^k,​2^k\cdots (2k+5)^k$,于是可以线性时间求出 $f(1),​f(2)\cdots f(k+3)$,最后套用拉格朗日插值法即可。
 +
 +总时间复杂度 $O(k)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=1e7+5,​MAXV=2e7+10,​Mod=998244353;​
 +int quick_pow(int x,int k){
 + int ans=1;
 + while(k){
 + if(k&​1)ans=1LL*ans*x%Mod;​
 + x=1LL*x*x%Mod;​
 + k>>​=1;​
 + }
 + return ans;
 +}
 +int prime[MAXV],​kpow[MAXV],​cnt;​
 +void Prime(int k){
 + kpow[1]=1;
 + _for(i,​2,​MAXV){
 + if(!kpow[i]) prime[cnt++]=i,​kpow[i]=quick_pow(i,​k);​
 + for(int j=0;​j<​cnt&&​i*prime[j]<​MAXV;​j++){
 + kpow[i*prime[j]]=1LL*kpow[i]*kpow[prime[j]]%Mod;​
 + if(i%prime[j]==0) break;
 + }
 + }
 +}
 +int inv[MAXN];
 +void get_inv(){
 + inv[1]=1;
 + _for(i,​2,​MAXN)
 + inv[i]=1LL*(Mod-Mod/​i)*inv[Mod%i]%Mod;​
 +}
 +int inv_frac[MAXN],​y[MAXN],​pre[MAXN],​suf[MAXN],​m;​
 +int Lagrange(int x,int n){
 + pre[0]=suf[n+1]=1;​
 + _rep(i,​1,​n)pre[i]=1LL*pre[i-1]*(x-i)%Mod;​
 + for(int i=n;​i;​i--)suf[i]=1LL*suf[i+1]*(x-i)%Mod;​
 + int ans=0,sign;
 + _rep(i,​1,​n){
 + sign=((n-i)&​1)?​-1:​1;​
 + ans=(ans+1LL*sign*y[i]*pre[i-1]%Mod*suf[i+1]%Mod*inv_frac[i-1]%Mod*inv_frac[n-i])%Mod;​
 + }
 + return ans;
 +}
 +int main()
 +{
 + int n=read_int(),​k=read_int();​
 + Prime(k);​get_inv();​
 + inv_frac[0]=1,​y[0]=0;​
 + _for(i,​1,​MAXN)inv_frac[i]=1LL*inv_frac[i-1]*inv[i]%Mod;​
 + _for(i,​1,​MAXV)kpow[i]=(kpow[i]+kpow[i-1])%Mod;​
 + _for(i,​1,​MAXN)y[i]=(y[i-1]+kpow[2*i-1]-kpow[i])%Mod;​
 + int ans=2LL*Lagrange(n,​k+3)*quick_pow(n,​Mod-2)%Mod;​
 + enter((ans+Mod)%Mod);​
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
2020-2021/teams/legal_string/jxm2001/多项式_1.1596382430.txt.gz · 最后更改: 2020/08/02 23:33 由 jxm2001