UVA 766 伯努利公式
题意
S k ( n ) = ∑ i = 1 n i k S_k(n)=\sum_{i=1}^n i^k Sk(n)=i=1∑nik
找到最小的M,以及
a
k
,
.
.
.
a
1
a_k,...a_1
ak,...a1 使得上式变成下式
S
k
(
n
)
=
1
M
(
a
k
+
1
∗
n
k
+
1
+
a
k
n
k
+
.
.
.
+
a
1
∗
n
+
a
0
)
S_k(n)=\frac{1}{M}(a_{k+1}*n^{k+1} +a_kn^k+...+a_1*n+a_0)
Sk(n)=M1(ak+1∗nk+1+aknk+...+a1∗n+a0)
题解
主要思路
该题就是套公式,公式理解都来自于这两个链接。
定义等幂和如下, 其中
m
,
n
≥
m,n \geq
m,n≥ 0:
S
k
(
n
)
=
∑
i
=
1
n
i
k
=
1
k
+
2
k
+
.
.
.
n
k
S_k(n)=\sum_{i=1}^n i^k=1^k+2^k+...n^k
Sk(n)=i=1∑nik=1k+2k+...nk
这数列和的公式必定是变量为n,次数为m+1次的多项式,称为伯努利多项式。
伯努利多项式的系数与 伯努利数
B
n
B_n
Bn 有密切关系如下:
S
k
(
n
)
=
1
k
+
1
∑
i
=
0
k
C
k
+
1
i
B
i
n
k
+
1
−
i
S_k(n)=\frac{1}{k+1} \sum_{i=0}^kC_{k+1}^i\,B_i\,n^{k+1-i}
Sk(n)=k+11i=0∑kCk+1iBink+1−i
而伯努利
B
i
B_i
Bi 可以通过递推得到
B
m
=
−
1
m
+
1
∑
i
=
0
m
−
1
C
m
+
1
i
B
i
B_m=-\frac{1}{m+1}\sum_{i=0}^{m-1} C_{m+1}^i B_i
Bm=−m+11i=0∑m−1Cm+1iBi
代入
B
0
=
1
B_0=1
B0=1 ,就可以得到一系列伯努利数了
算法过程
- 代入公式,把系数用分数求出来
- 再把这些分数形式的系数乘上他们分母的公倍数,就能让系数都为整数,并且 M M M 最小。
代码
#include <stdio.h>
#include <string.h>
long long gcd(long long a, long long b) {
if (!b) return a;
return gcd(b, a % b);
}
long long lcm(long long a, long long b) {
a = a / gcd(a, b) * b;
if (a < 0) a = -a;
return a;
}
struct Fraction {
long long a, b;
Fraction() {a = 0; b = 1;}
Fraction(long long x) {
a = x; b = 1;
}
Fraction(long long x, long long y) {
a = x; b = y;
}
void deal() {
if (b < 0) {b = -b; a = -a;}
long long k = gcd(a, b);
if (k < 0) k = -k;
a /= k; b /= k;
}
Fraction operator+(Fraction p) {
Fraction ans;
ans.b = lcm(b, p.b);
ans.a = ans.b / b * a + ans.b / p.b * p.a;
ans.deal();
return ans;
}
Fraction operator-(Fraction p) {
Fraction ans;
ans.b = lcm(b, p.b);
ans.a = ans.b / b * a - ans.b / p.b * p.a;
ans.deal();
return ans;
}
Fraction operator*(Fraction p) {
Fraction ans;
ans.a = a * p.a;
ans.b = b * p.b;
ans.deal();
return ans;
}
Fraction operator/(Fraction p) {
Fraction ans;
ans.a = a * p.b;
ans.b = b * p.a;
ans.deal();
return ans;
}
void operator=(int x) {
a = x;
b = 1;
}
void print() {
printf("%lld/%lld\n", a, b);
}
};
const int N = 25;
Fraction B[N], C[N][N], a[N];
long long L;
void init() {
for (int i = 0; i < N; i++) {
C[i][0] = 1;
C[i][i] = 1;
for (int j = 1; j < i; j++) {
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
B[0] = 1;
for (int i = 1; i <= 20; i++) {
B[i] = 0;
for (int j = 0; j < i; j++) B[i] = B[i] - C[i + 1][j] * B[j];
B[i] = B[i] / (i+1);
}
}
int main() {
// freopen("in.text","r",stdin);
int cas,k;
init();
scanf("%d", &cas);
while (cas--) {
L = 1;
scanf("%d", &k);
for (int i = 0; i <= k; i++){
a[i] = C[k+ 1][i] * B[i] * Fraction(1, k+ 1);
L = lcm(L, a[i].b);
}
printf("%lld ", L);
a[1] = a[1] + 1;
for (int i = 0; i <=k; i++)printf("%lld ", L / a[i].b * a[i].a);
printf("0\n");
if (cas) printf("\n");
}
return 0;
}