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.

Input
T -- number of cases
for each case:
  n (1 <= n < 2^31)

Output
for each case:
  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 }

 

posted @ 2017-10-18 20:55  人棍王楼下的AI  阅读(168)  评论(0编辑  收藏  举报