题目:http://codeforces.com/contest/622/problem/F
设 f(x) = 1^k + 2^k + ... + n^k
则 f(x) - f(x-1) = x^k
因为差值是 k 次的,所以 f 的次数应该是 k+1;
算出 k+2 个值就可以用拉格朗日插值求解了;
但是 k^2 会 T;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=1e6+5,mod=1e9+7; int n,k,f[xn]; int pw(ll a,int b) { ll ret=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1)ret=(ret*a)%mod; return ret; } int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;} int main() { scanf("%d%d",&n,&k); for(int i=1;i<=k+2;i++)f[i]=upt(f[i-1]+pw(i,k));//!k+1 int sum=0; for(int i=1;i<=k+2;i++) { ll s1=1,s2=1; for(int j=1;j<=k+2;j++) { if(i==j)continue; s1=s1*(n-j)%mod; s2=s2*(i-j)%mod; } sum=(sum+s1*pw(s2,mod-2)%mod*f[i])%mod; } printf("%d ",upt(sum)); return 0; }
由于 x 都是连续的,所以可以直接预处理阶乘;
分母部分的阶乘要跳过0,比较麻烦...一开始准备先算一个值,然后每次修改,但是失败了...
于是参考了一下 TJ,原来可以分正负两部分计算!
分子万一乘到0怎么办?先特判一下 n<=k+2 即可;
别忘了阶乘数组是 ll 或局部开 ll !
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=1e6+5,mod=1e9+7; int n,k,f[xn]; ll fac[xn];//ll int pw(ll a,int b) { ll ret=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1)ret=(ret*a)%mod; return ret; } int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;} ll get(int i) { if(i==k+2)return fac[i-1]; return fac[i-1]*fac[k+2-i]%mod; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=k+2;i++)f[i]=upt(f[i-1]+pw(i,k));//!k+1 if(n<=k+2){printf("%d ",f[n]); return 0;}//!! int sum=0; ll s1=1; fac[0]=1; for(int i=1;i<=k+2;i++)fac[i]=fac[i-1]*i%mod; for(int i=1;i<=k+2;i++)s1=s1*(n-i)%mod; //for(int i=2;i<=k+2;i++)s2=s2*(1-i)%mod; for(int i=1;i<=k+2;i++) { ll t1=s1*pw(n-i,mod-2)%mod; ll s2=pw(get(i),mod-2); if((k+2-i)%2)s2=-s2; //if(i>1)s2=s2*pw(upt(i-1-k-2),mod-2)%mod*(i-1)%mod; sum=(sum+t1*s2%mod*f[i])%mod; } printf("%d ",upt(sum)); return 0; }