组合数学一个知识点
贝尔数:讲n个不同数划分为任意集合组合的方法数
求解方法:贝尔三角形 O(n^2)
1
1 2
2 3 5
5 7 10 15
15 20 27 37 52
52 67 87 114 151 203
203 255 322 409 523 674 877
cpp
int A[N];
A[0] = 1;
B[0] = 1;
for (int i = 1; i < N; i++) {
int prev = A[0];
A[0] = A[i-1];
for (int j = 1; j <= i; j++) {
int tmp = A[j];
A[j] = (A[j-1] + prev) % MOD;
prev = tmp;
}
B[i] = A[0];
}
大数据可用递推公式优化为O(n log(n))
例题:
E. Partition of a Binary String
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5000+5;
const int MOD=998244353;
int n;
int f[N], B[N];
// 预处理交替子串的划分方案数 f 和贝尔数 B
void precompute() {
f[0] = 1;
f[1] = 0;
f[2] = 1;
f[3] = 1;
for (int i = 4; i < N; i++) {
f[i] = (f[i-2] + f[i-3]) % MOD;
}
int A[N];
A[0] = 1;
B[0] = 1;
for (int i = 1; i < N; i++) {
int prev = A[0];
A[0] = A[i-1];
for (int j = 1; j <= i; j++) {
int tmp = A[j];
A[j] = (A[j-1] + prev) % MOD;
prev = tmp;
}
B[i] = A[0];
}
}
void solve() {
cin>>n;char tp,pre;
int num1=0,num0=0,ans=1,k=0,sum=0;bool flag=0;
cin>>pre;
if(n==1){
cout<<1<<' '<<1<<endl;return;
}
for(int i=1;i<n;i++){
cin>>tp;
if(tp==pre){
if(flag){
k++;
ans=ans*f[k]%MOD;sum+=k;
flag=0;k=0;
}
else{
if(pre=='1')num1++;
else num0++;
}
}
else{
flag=1;k++;
}
if(i==n-1){
if(flag){
k++;
ans=ans*f[k]%MOD;sum+=k;
}
else{
if(tp=='1')num1++;
else num0++;
}
}
else pre=tp;
}
ans=ans*B[num1]%MOD;
ans=ans*B[num0]%MOD;
cout<<2*sum+num1+num0<<' '<<ans<<endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
precompute();
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}