[斯特林数][自然数幂和] Jzoj P4220 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

 

题解

  • 这道题显然就是要求
  • 我们先考虑一下若何求一个i^k,对于第二类斯特林数我们知道Si,j表示为把i个有区别的球放入j个无区别的盒子的方案数(不存在空盒)
  • 显然i^k也可以理解为将i个不同的盒子放入k个不同的球的方案数(允许空盒)
  • 现在把允许空盒转换为每个盒子至少放一个球的方案数,对于存在k-j空盒的方案数就是 S[k][j]*C(i,j)*j!
  • 这样的话我们就可以得出
  • 已知,
  • 所以,
  • 最后的话,这个东西怎么求呢,可以预处理斯特林数,再加个快速幂和防爆longlong的奇技淫巧就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define ll long long
 5 #define N 2010
 6 using namespace std;
 7 ll k,n,m,p,ans,s[N][N];
 8 ll mul(ll x,ll y)
 9 {
10     ll l=1e6,a1=x/l,a2=x%l,b1=y/l,b2=y%l;
11     return (a1*b1%p*l%p*l%p+a1*b2%p*l%p+b1*a2%p*l%p+a2*b2%p)%p;
12 }
13 ll ksm(ll a,ll b)
14 {
15     ll r=1;
16     for (;b;b>>=1,a=mul(a,a)) if (b&1) r=mul(r,a);
17     return r;
18 }
19 ll calc(ll n)
20 {
21     ll ans=0;
22     for (ll i=0;i<=k;i++)
23     {
24         ll r=s[k][i];
25         for (ll j=n+1;j>=n+1-i;j--) r=mul(r,(j%(i+1)==0)?j/(i+1):j);
26         ans=(ans+r)%p;
27     }
28     return ans;
29 }
30 int main()
31 {
32     scanf("%lld%lld%lld%lld",&k,&n,&m,&p),s[0][0]=1;
33     if (k>2000)
34     {
35         for (ll i=m;i<=n;i++) ans=(ans+ksm(i,k))%p;
36         printf("%lld",ans); return 0;
37     }
38     for (ll i=1;i<=k;i++) for (ll j=1;j<=i;j++) s[i][j]=(s[i-1][j-1]+j*s[i-1][j]%p+p)%p;
39     printf("%lld",(calc(n)-calc(m-1)+p)%p);
40 }

 

posted @ 2019-01-27 20:22  BEYang_Z  阅读(434)  评论(0编辑  收藏  举报