[斯特林数][自然数幂和]JZOJ 4220 WYF的盒子

Description

WYF有一个精致的k维立方体盒子(2维为正方形,3维为正方体,以此类推)。这个盒子的边长为n,里面有一个边长为n-1的盒子,边长为n-1的盒子里面还有一个边长为n-2的盒子……最里面的盒子边长为m。现在WYF想知道这n-m+1个盒子的k维体积和模p的余数。
 

Input

输入共一行包含4个正整数k, n, m, p。

Output

输出共一行包含1个正整数,表示n-m+1个盒子的k维体积之和模p的余数。
 

Sample Input

输入1:
4 2 2 97

输入2:
1 100 1 10007
 

Sample Output

输出1:
16
【样例说明】
边长为2的4维立方体的4维体积为16。

输出2
5050
 

Data Constraint

分析

不会数学公式,不方便打,不妨看ZZY大爷的吧

 

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll C=1e6;
ll k,n,m,p,s[2010][2010];

ll Multi(ll a,ll b) {
    ll x=a%C,y=b%C,ax=a/C,ay=b/C;
    return (x*y%p+x*ay%p*C%p+y*ax%p*C%p+ax*ay%p*C%p*C%p)%p;
}
//AntiExplodeMulti

ll Power(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=Multi(x,x)) if (y&1) ans=Multi(ans,x);return ans;}

void Pre_Process() {
    s[0][0]=1;
    for (int i=1;i<=k;++i) 
        for (int j=1;j<=i;++j) 
            s[i][j]=(s[i-1][j-1]+Multi(j,s[i-1][j]))%p;
}

ll Calc(ll x) {
    ll ans=0;
    for (int i=0;i<=k;++i) {
        ll pow=s[k][i];
        for (ll j=x-i+1;j<=x+1;++j)
            pow=Multi(pow,j%(i+1)==0?j/(i+1):j);
        ans=(ans+pow)%p;
    }
    return ans;
}

int main() {
    scanf("%lld%lld%lld%lld",&k,&n,&m,&p);
    ll ans=0;
    if (n-m<=5000ll) for (ll i=n;i>=m;--i) ans=(ans+Power(i,k))%p;
    else {
        Pre_Process();
        ans=((Calc(n)-Calc(m-1))%p+p)%p;
    }
    printf("%lld",ans);
}
View Code

 

posted @ 2019-01-27 21:13  Vagari  阅读(178)  评论(0编辑  收藏  举报