WYF的盒子

Description

给出n,m,k,p,求

i=nmikmodp

Solution

用什么

首先,自然数幂求和,好多方法啊。解决自然数幂和的各种方法
由于第一类斯特林数不用中国剩余定理来对于mod操作特殊处理,所以这个好。
用前缀和思想,再加上用第一类斯特林数处理自然数幂和,然后就能过了吗。

两个数乘起来爆long long了!

怎么办。
看处理两数相乘的黑科技

注意

不要在运算的时候mod 太多次,mod的速度十分的慢啊!

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
ll i,j,k,l,t,n,m,ans,mo;
ll s[2060][2060],f[2060];
ll qsc(ll x,ll y){
    ll a1=x/1000000,a2=x%1000000,b1=y /1000000,b2=y%1000000,z=0;
    z=(a1*b1%mo*1000000%mo*1000000%mo);
    z=(z+a1*b2%mo*1000000%mo);
    z=(z+a2*b2%mo);
    z=(z+a2*b1%mo*1000000%mo);
    return z%mo;
}
ll qsm(ll x,ll y){
    ll z=1;
    while(y!=0){
        if(y&1!=0)z=qsc(z,x);
        x=qsc(x,x);
        y=y /2;
    }
    return z;
}
ll stirling(ll x){
    ll i,j,l,o;
    memset(f,0,sizeof(f));
    if(x%2==0)f[1]=qsc(x/2,(x+1));
    else f[1]=qsc((x+1)/2,x);
    f[0]=x%mo;
    fo(i,2,k){
        l=1;
        fo(j,x-i+1,x+1){
            if(j%(i+1)==0)l=qsc(l,(j/(i+1)));
            else l=qsc(l,j);
        }
        f[i]=l;
        fo(j,0,i-1){
            if((i+j)%2==0)o=1;else o=-1;
            f[i]=(f[i]-(qsc(o*f[j],s[i][j]))+mo);
            f[i]=(f[i]+mo)%mo;
        }
    }
    return f[k]%mo;
}
int main(){
    scanf("%lld%lld%lld%lld",&k,&n,&m,&mo);
    if(n>m)t=n,n=m,m=t;
    if(m-n<=5000){
        fo(i,n,m){
            ans=(ans+qsm(i,k))%mo;
        }
        printf("%lld\n",ans);
        return 0;
    }
    s[0][0]=1;
    fo(i,0,k)s[i][i]=1;
    fo(i,1,k){
        fo(j,1,i-1){
            s[i][j]=(qsc(s[i-1][j],(i-1))+s[i-1][j-1])%mo;
        }
    }
    ans=(stirling(m)-stirling(n-1)+mo)%mo;
    printf("%lld\n",ans);
}

你可能感兴趣的:(自然数幂和,第一类斯特林数,快速乘,WYF的盒子,等幂和)