BellTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 666 Accepted Submission(s): 286
Problem 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
Sample Output
|
Bell数:讲解特详细
看会上面这个,就可以KO这道题了。
先找到95041567的小于100的质因子:
#include <cstdio> int main() { int n = 95041567; while(n != 1) { for(int i = 2; i <= 100; i++)//没有必要判断是否是质数 就可以找到。。。 { if(n % i == 0) { printf("%d\n", i); n /= i; break; } } } return 0; }
我构建的矩阵如下:
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define LL long long #define debug printf("1\n"); using namespace std; int m[6] = {0, 31, 37, 41, 43, 47}; int rm[6]; int a[6];//方程组x % m = a int B[6][60][60];//保存对m[i]取余后的 Bell数 int F[60]; void getBell(int id, int MOD)//预处理贝尔数 { B[id][0][1] = 1; for(int i = 1; i <= 50; i++) { for(int j = 1; j <= i+1; j++) { if(j == 1) B[id][i][j] = B[id][i-1][i]; else B[id][i][j] = (B[id][i-1][j-1] + B[id][i][j-1]) % MOD; } } } struct MATRIX { struct Matrix{ int a[60][60]; int r, c; }; Matrix ori, res; void init(int id, int p)//建立p*p矩阵 { for(int i = 1; i <= p; i++) F[i] = B[id][i][1] % p; //debug; ori.r = res.r = ori.c = res.c = p; memset(ori.a, 0, sizeof(ori.a)); memset(res.a, 0, sizeof(res.a)); for(int i = 1; i <= p; i++) { res.a[i][i] = 1; if(i < p) ori.a[i][i] = ori.a[i+1][i] = 1; else ori.a[i][i] = ori.a[1][i] = ori.a[2][i] = 1; } } Matrix multi(Matrix x, Matrix y, int MOD) { Matrix z; memset(z.a, 0, sizeof(z.a)); z.r = x.r; z.c = y.c; for(int i = 1; i <= x.r; i++) { for(int k = 1; k <= x.c; k++) { if(x.a[i][k] == 0) continue; for(int j = 1; j <= y.c; j++) z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % MOD) % MOD; } } return z; } void solve(int n, int MOD) { while(n) { if(n & 1) res = multi(ori, res, MOD); ori = multi(ori, ori, MOD); n >>= 1; } } }; MATRIX MA; struct CRT { int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); } void exgcd(int a, int b, int &d, int &x, int &y) { if(b == 0) {d = a, x = 1, y = 0;} else { exgcd(b, a%b, d, y, x); y -= x * (a / b); } } int solve(int l, int r, int *m, int *a) { int LCM = 1; for(int i = l; i <= r; i++) LCM = LCM / gcd(LCM, m[i]) * m[i]; for(int i = l+1; i <= r; i++) { int A = m[l], B = m[i], d, x, y, c = a[i] - a[l]; exgcd(A, B, d, x, y); if(c % d) return -1; int mod = m[i] / d; int k = ((x * c / d) % mod + mod) % mod; a[l] = m[l] * k + a[l]; m[l] = m[l] / d * m[i]; } if(a[l] == 0) return LCM; return a[l]; } }; CRT crt; int main() { for(int i = 1; i <= 5; i++) getBell(i, m[i]); int t; int n; scanf("%d", &t); while(t--) { scanf("%d", &n); if(n <= 50) { for(int i = 1; i <= 5; i++) a[i] = B[i][n][1]; memcpy(rm, m, sizeof(m)); printf("%d\n", crt.solve(1, 5, rm, a)); continue; } for(int i = 1; i <= 5; i++) { MA.init(i, m[i]);//构建矩阵 int temp = n / m[i]; if(n % m[i] == 0) temp -= 1; MA.solve(temp, m[i]); int remain = n % m[i];//找到位置 即第多少列 if(remain == 0) remain = m[i]; a[i] = 0; for(int j = 1; j <= m[i]; j++)//直接求解当前列的值就可以了 a[i] = (a[i] + (MA.res.a[j][remain] * F[j]) % m[i]) % m[i]; } memcpy(rm, m, sizeof(m));//一开始忘了这个了。。。 printf("%d\n", crt.solve(1, 5, rm, a));//求解 } return 0; }