贝尔数:https://www.cnblogs.com/yuyixingkong/p/4480349.html
利用Touchard同余性质,
B
n
+
p
=
(
B
n
+
B
n
+
1
)
m
o
d
p
(
p
∈
p
r
i
m
e
)
B_{n + p} = (B_n + B_{n + 1}) \mod p (p \in prime)
Bn+p=(Bn+Bn+1)modp(p∈prime)
当 n 较小时可以用贝尔数的计算式
n
2
n ^2
n2 计算得出,当 n 较大时可以记忆化搜索,预处理n < 1000的贝尔数。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int t,mod,n;
ll dp[maxn],fact[maxn],ifact[maxn];
ll C(int x,int y) {
if(y > x || y < 0) return 0;
return fact[x] * ifact[y] % mod * ifact[x - y] % mod;
}
ll fpow(ll a,ll b) {
ll r = 1;
while(b) {
if(b & 1) r = r * a % mod;
b >>= 1;
a = a * a % mod;
}
return r;
}
ll dfs(ll x) {
if(x < 0) return 0;
if(dp[x]) return dp[x];
return dp[x] = (dfs(x - mod) + dfs(x - mod + 1)) % mod;
}
int main() {
scanf("%d",&t);
while (t--) {
memset(dp,0,sizeof dp);
memset(fact,0,sizeof fact);
memset(ifact,0,sizeof ifact);
scanf("%d%d",&n,&mod);
fact[0] = 1;
for (int i = 1; i <= mod - 1; i++)
fact[i] = fact[i - 1] * i % mod;
ifact[mod - 1] = fpow(fact[mod - 1],mod - 2);
for (int i = mod - 2; i >= 0; i--)
ifact[i] = ifact[i + 1] * (i + 1) % mod;
dp[0] = dp[1] = 1;
for(int i = 2; i <= 1000; i++)
for(int j = 0; j < i; j++)
dp[i] = (dp[i] + C(i - 1,j) * dp[j] % mod) % mod;
printf("%lld\n",dfs(n));
}
return 0;
}