1 条题解
-
1
题解
先通过递推式求得伯努利数,然后用公式并将中间的,变成,后面再加上,化进去就行了。简而言之就是由数学伯努利公式代入,通分化简就可以。
标程
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <iostream> #include <string> #include <ctime> #define LOCAL const int MAXN = 20 + 10; const double Pi = acos(-1.0); using namespace std; typedef long long ll; ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } struct Num { ll a, b; // 分数,b为分母 Num(ll x = 0, ll y = 0) { a = x; b = y; } void update() { ll tmp = gcd(a, b); a /= tmp; b /= tmp; } Num operator + (const Num &c) { ll fz = a * c.b + b * c.a, fm = b * c.b; if (fz == 0) return Num(0, 1); ll tmp = gcd(fz, fm); return Num(fz / tmp, fm / tmp); } } B[MAXN], A[MAXN]; ll C[MAXN][MAXN]; void init() { // 预处理组合数 int i, j; for (i = 0; i < MAXN; i++) C[i][0] = C[i][i] = 1; for (i = 2; i < MAXN; i++) for (j = 1; j < MAXN; j++) C[i][j] = C[i - 1][j] + C[i - 1][j - 1]; // 预处理伯努利数 B[0] = Num(1, 1); for (i = 1; i < MAXN; i++) { Num tmp = Num(0, 1), add; for (j = 0; j < i; j++) { add = B[j]; add.a *= C[i + 1][j]; tmp = tmp + add; } if (tmp.a) tmp.b *= -(i + 1); tmp.update(); B[i] = tmp; } } void work() { int n; scanf("%d", &n); ll M = n + 1, flag = 0, Lcm; A[0] = Num(0, 1); int i; for (i = 1; i <= n + 1; i++) { if (B[n + 1 - i].a == 0) { A[i] = Num(0, 1); continue; } Num tmp = B[n + 1 - i]; tmp.a *= C[n + 1][i]; // C[n+1][i] = C[n + 1][n + 1 - i] tmp.update(); if (flag == 0) { Lcm = flag = tmp.b; } A[i] = tmp; } A[n] = A[n] + Num(n + 1, 1); for (i = 2; i <= n + 1; i++) { if (A[i].a == 0) continue; Lcm = (Lcm * A[i].b) / gcd(Lcm, A[i].b); } if (Lcm < 0) Lcm *= -1; M *= Lcm; printf("%lld", M); for (i = n + 1; i >= 0; i--) { printf(" %lld", A[i].a * Lcm / A[i].b); } } int main() { init(); work(); return 0; }
- 1
信息
- ID
- 708
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者