HDU4767 Bell Bell数的性质,矩阵快速幂
Description
What? MMM is learning Combinatorics!?
Looks like she is playing with the bell sequence now:
bell[n] = number of ways to partition of the set {1, 2, 3, ..., n}
e.g. n = 3:
{1, 2, 3}
{1} {2 3}
{1, 2} {3}
{1, 3} {2}
{1} {2} {3}
so, bell[3] = 5
MMM wonders how to compute the bell sequence efficiently.
Looks like she is playing with the bell sequence now:
bell[n] = number of ways to partition of the set {1, 2, 3, ..., n}
e.g. n = 3:
{1, 2, 3}
{1} {2 3}
{1, 2} {3}
{1, 3} {2}
{1} {2} {3}
so, bell[3] = 5
MMM wonders how to compute the bell sequence efficiently.
Input
T -- number of cases
for each case:
n (1 <= n < 2^31)
for each case:
n (1 <= n < 2^31)
Output
for each case:
bell[n] % 95041567
bell[n] % 95041567
Sample Input
6
1
2
3
4
5
6
Sample Output
1
2
5
15
52
203
题意:输出$Bell$数对$95041567$取模
本身并不是对质数取模,一开始可以对模数分解
这样子所有的质数模就不超过50
考虑公式$ B_{n+p}\equiv B_{n}+B_{n+1}\mod p$
我们可以尝试构造一个矩阵
使用矩阵快速幂加速
最后用中国剩余定理合并即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 template<typename T>T read(){ 5 T x=0,f=1;char c=getchar(); 6 7 for(;!isdigit(c);c=getchar())if(c=='-')f=-1; 8 for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48); 9 10 return x*f; 11 } 12 13 const int maxn=100010; 14 typedef long long ll; 15 16 const int mod[5]={47,43,41,37,31}; 17 const int Mod=95041567; 18 19 int n,Bell[60],C[60],kase; 20 21 int A[50]; 22 23 struct matrix{ 24 int m[50][50]; 25 matrix(){ 26 memset(m,0,sizeof m); 27 }; 28 matrix(int v){ 29 memset(m,0,sizeof m); 30 for(int i=0;i<50;++i)m[i][i]=v; 31 } 32 }; 33 34 matrix mul(matrix a,matrix b){ 35 matrix ret; 36 for(int i=0;i<50;++i){ 37 for(int j=0;j<50;++j){ 38 for(int k=0;k<50;++k){ 39 (ret.m[i][j]+=1ll*a.m[i][k]*b.m[k][j]%mod[kase]); 40 (ret.m[i][j])%=mod[kase]; 41 } 42 } 43 } 44 return ret; 45 } 46 47 matrix fpm(matrix a,ll b){ 48 matrix ret(1); 49 for(;b;b>>=1,a=mul(a,a)) 50 if(b&1)ret=mul(ret,a); 51 return ret; 52 } 53 54 int fpm(int a,int i){ 55 int ret=1,b=mod[i]-2; 56 for(;b;b>>=1,a=a*a%mod[i]) 57 if(b&1)ret=ret*a%mod[i]; 58 return ret; 59 } 60 61 int CRT(){ 62 int ret=0; 63 for(int i=0;i<5;++i){ 64 int mm=Mod/mod[i]; 65 int inv=fpm(mm%mod[i],i); 66 ret=(ret+1ll*A[i]*mm*inv)%Mod; 67 } 68 return ret; 69 } 70 71 void solve(){ 72 scanf("%d",&n); 73 if(n<48){ 74 printf("%d\n",Bell[n]); 75 return; 76 } 77 for(kase=0;kase<5;++kase){ 78 matrix tmp,vec; 79 80 for(int i=0;i<mod[kase];++i) 81 vec.m[i][0]=Bell[i]%mod[kase]; 82 for(int i=0;i<mod[kase]-1;++i) 83 tmp.m[i][i]=tmp.m[i][i+1]=1; 84 tmp.m[mod[kase]-1][mod[kase]-1]=1; 85 tmp.m[mod[kase]-1][0]=1; 86 tmp.m[mod[kase]-1][1]=1; 87 88 tmp=fpm(tmp,n/mod[kase]); 89 vec=mul(tmp,vec); 90 91 A[kase]=vec.m[n%mod[kase]][0]; 92 } 93 94 printf("%d\n",CRT()); 95 } 96 97 void init(){ 98 Bell[0]=Bell[1]=1; 99 C[0]=1; 100 for(int i=2;i<50;++i){ 101 C[i-1]=Bell[i-1]; 102 for(int j=i-2;~j;--j) 103 C[j]=(C[j]+C[j+1])%Mod; 104 Bell[i]=C[0]; 105 } 106 107 } 108 109 int main(){ 110 #ifndef ONLINE_JUDGE 111 freopen("chk.in","r",stdin); 112 freopen("chk.out","w",stdout); 113 #endif 114 115 init(); 116 for(int T=read<int>()+1;--T;){ 117 solve(); 118 } 119 return 0; 120 }