题解 CF622F 【The Sum of the k-th Powers】

HenryHuang

2020-06-16 17:58:38

Solution

### 题意 求 $\sum_{i=1}^ni^k(1\le n\le 10^9,0\le k\le 10^6)$。 ### 题解 不要以为没人会卡 $O(k\log_2k)$ 做法的... 真的有这种毒瘤... 首先 $O(k\log_2k)$ 的做法及证明其他题解都已经讲的很清楚了,在这里不再赘述。 首先如何考虑求出插值所需要的点值,即当 $n=1,2,\cdots,k+2$ 时的值。 注意到 $f(i)=i^k$ 是一个完全积性函数,所以我们只需要求出当 $i$ 为质数时候的值,然后线性筛即可,最后做一遍前缀和即可得到答案。这样的复杂度大约是 $O(k)$ 的,因为我们只在质数的位置进行了快速幂。 由于我们取的是一段连续的点值,所以在插值的时候只需要维护一个前缀积、后缀积、阶乘及阶乘逆元即可。 线性求逆元大概就是先求出 $\frac {1}{n!}$,然后 $\frac {1}{(n-1)!}=\frac {1}{n!}\times n$。事实上这个方法可以在线性时间内处理出任意的 $n$ 个已知数的逆元。 然后这个题就完了,总时间复杂度为 $O(k)$。 贴代码 ``` /*---Author:HenryHuang---*/ #include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; const int p=1e9+7; int n,k; int ksm(int a,int b,int p){ int ans=1; while(b){ if(b&1) ans=1ll*ans*a%p; b>>=1,a=1ll*a*a%p; } return ans; } int pri[maxn],mi[maxn],cnt; bool P[maxn]; void init(){ mi[1]=1; for(int i=2;i<=k+2;++i){ if(!P[i]) mi[i]=ksm(i,k,p),pri[++cnt]=i; for(int j=1;j<=cnt&&i*pri[j]<=k+2;++j){ P[i*pri[j]]=1; mi[i*pri[j]]=1ll*mi[i]*mi[pri[j]]%p; if(i%pri[j]==0) break; } } for(int i=1;i<=k+2;++i) mi[i]=(mi[i]+mi[i-1]>p?mi[i]+mi[i-1]-p:mi[i]+mi[i-1]); } int f[maxn],g[maxn]; int fac[maxn],inv[maxn],ans; int main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n>>k; init(); f[0]=g[0]=1; if(n<=k+2) cout<<mi[n]<<'\n',exit(0); f[0]=g[k+3]=fac[0]=inv[0]=1; for(int i=1;i<=k+2;++i) f[i]=1ll*f[i-1]*(n-i)%p; for(int i=k+2;i>=1;--i) g[i]=1ll*g[i+1]*(n-i)%p; for(int i=1;i<=k+2;++i) fac[i]=1ll*fac[i-1]*i%p; inv[k+2]=ksm(fac[k+2],p-2,p); for(int i=k+1;i>=1;--i) inv[i]=1ll*inv[i+1]*(i+1)%p; for(int i=1;i<=k+2;++i){ int a=1ll*f[i-1]*g[i+1]%p; int b=1ll*inv[i-1]*((k-i)&1?(p-inv[k+2-i]):inv[k+2-i])%p; ans=(ans+1ll*mi[i]*a%p*b%p)%p; } cout<<ans<<'\n'; return 0; } ```