自然数幂和,
咳咳这个就不用说了。当然不要太暴力了,像求幂可以用快速幂。
我们仔细观察发现,对于求自然数k次方和的公式应该是k+1次的。那么我们可以想到,列个方程组让高斯消元解决,然后得到各项系数后直接代入即可。
复杂度 O(k3)
发现方法有点问题,先留坑
我们设 f(n,k)=∑ni=1ik
那么现在我们要计算f(n,k)怎么办呢?
我们采用分治思想。
如果n是奇数那么
f(n,k)=f(n−1,k)+nk
否则,我们可以先求出n/2的f,然后对于n/2+1~n中的每个数都可以表示为n/2+i
那么
f(n,k)=f(n/2,k)+∑n/2i=1∑kj=0Cjk∗ij∗(n/2)k−j
调换一下
f(n,k)=f(n/2,k)+∑kj=0Cjk∗f(n/2,j)∗(n/2)k−j
于是对于每一个n的f我们需要 O(k2) ,一共有log n层,算上快速幂的复杂度
总共是 O(k2lognlogk)
分拉格朗日插值法和牛顿插值法,我不会……
同不会
该方法来自GEOTCBRL小学生数学题题解,%%%。
我们设
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll su[2000+10][2000+10],f[2000+10];
ll i,j,k,l,t,n,m,p;
ll qsc(ll x,ll y){
ll a1=x/1000000,a2=x%1000000,b1=y/1000000,b2=y%1000000;
ll t=a1*b1%p*1000000%p*1000000%p;
t=(t+a2*b2%p);
t=(t+a1*b2%p*1000000%p);
t=(t+a2*b1%p*1000000%p);
return t%p;
}
ll qsm(ll x,ll y){
if (!y) return 1;
ll t=qsm(x,y/2);
t=qsc(t,t);
if (y%2) t=qsc(t,x);
return t;
}
ll get(ll n){
if (!n) return 0;
if (n<=k){
t=0;
fo(i,1,n){
l=1;
fo(j,1,k)
l=qsc(l,i);
t=(t+l)%p;
}
return t;
}
fo(i,0,k) f[i]=0;
if (n%2==0) f[1]=qsc(n/2,n+1);
else f[1]=qsc(n,(n+1)/2);
f[1]=(f[1]+1)%p;
f[0]=n%p;
fo(i,2,k){
t=1;
fo(j,n+1-i,n+1)
if (j%(i+1)==0) t=qsc(t,j/(i+1));else t=qsc(t,j);
f[i]=t;
fo(j,0,i-1){
if ((j+i)%2==0) l=1;else l=-1;
f[i]=((f[i]-qsc(l*su[i][j],f[j]))%p+p);
}
f[i]=f[i]%p;
}
return ((f[k]-1)%p+p)%p;
}
int main(){
scanf("%lld%lld%lld%lld",&k,&n,&m,&p);
if (n-m<=5000){
t=0;
fo(i,m,n) t=(t+qsm(i,k));
printf("%lld\n",t%p);
return 0;
}
su[0][0]=1;
fo(i,1,k) su[i][0]=0,su[i][i]=1;
fo(i,1,k)
fo(j,1,i-1)
su[i][j]=(su[i-1][j-1]+qsc(i-1,su[i-1][j]));
printf("%lld\n",((get(n)-get(m-1))%p+p)%p);
}