[LOJ 6055]「from CommonAnts」一道数学题 加强版(神仙拉格朗日插值) | 错题本

文章目录

题目

「from CommonAnts」一道数学题 加强版

分析

F k ( n ) = f ( k , n ) F_k(n) = f(k, n) Fk(n)=f(k,n),统计每个 x k x^k xk 的贡献可以得到 F k ( n ) = ∑ i = 0 n − 1 ( 2 n − i − 1 ⋅ i k ) + n k F_k(n) = \sum_{i = 0}^{n - 1} \left(2^{n - i - 1} \cdot i^k\right) + n^k Fk(n)=i=0n1(2ni1ik)+nk 具体来说可以画个二叉树理解:树上深度为 i i i 的结点的权值为 ( n − i + 1 ) k (n - i + 1)^k (ni+1)k,根以及他的右子树权值和为 F k ( n ) F_k(n) Fk(n),根的左儿子和根的左儿子的右子树权值和 F k ( n − 1 ) F_k(n - 1) Fk(n1),以此类推。

显然不能直接插,因为 n n n 在指数上。化简一下:
F k ( n ) = ∑ i = 0 n − 1 ( 2 n − i − 1 ⋅ i k ) + n k = 2 n − 1 ∑ i = 0 n − 1 i k 2 i + n k \begin{aligned} F_k(n) &= \sum_{i = 0}^{n - 1} \left(2^{n - i - 1} \cdot i^k\right) + n^k \\ &= 2^{n - 1}\sum_{i = 0}^{n - 1} \frac{i^k}{2^i} + n^k \end{aligned} Fk(n)=i=0n1(2ni1ik)+nk=2n1i=0n12iik+nk a = 1 2 a = \frac{1}{2} a=21,则 F k ( n ) = 2 n − 1 ∑ i = 0 n − 1 a i i k + n k F_k(n) = 2^{n - 1}\sum_{i = 0}^{n - 1} a^ii^k + n^k Fk(n)=2n1i=0n1aiik+nk 指数转下降幂可以方便错位相减找递推式,进而找到指数函数的多项式形式: F k ( n ) = 2 n − 1 ∑ i = 0 n − 1 ( a i ∑ j = 0 k { k j } i j ‾ ) + n k = 2 n − 1 ∑ j = 0 k { k j } ∑ i = 0 n − 1 a i i j ‾ + n k \begin{aligned} F_k(n) &= 2^{n - 1}\sum_{i = 0}^{n - 1}\left(a^i \sum_{j = 0}^k {k \brace j} i^{\underline j}\right) + n^k \\ &= 2^{n - 1} \sum_{j = 0}^k {k \brace j} \sum_{i = 0}^{n - 1} a^ii^{\underline j} + n^k \end{aligned} Fk(n)=2n1i=0n1(aij=0k{jk}ij)+nk=2n1j=0k{jk}i=0n1aiij+nk S k ( n ) = ∑ i = 0 n − 1 a i i k ‾ S_k(n) = \sum_{i = 0}^{n - 1} a^ii^{\underline k} Sk(n)=i=0n1aiik,则 F k ( n ) = 2 n − 1 ∑ j = 0 k { k j } S j ( n ) + n k F_k(n) = 2^{n - 1} \sum_{j = 0}^k {k \brace j} S_j(n) + n^k Fk(n)=2n1j=0k{jk}Sj(n)+nk

指数转下降幂:
{ n m } {n \brace m} {mn} 表示第二类斯特林数,即“ n n n 个不同的球,放入 m m m 个相同的盒子,盒子不可以为空的方案数”。有公式 n k = ∑ i = 0 k { k i } ⋅ i ! ⋅ C n i n^k = \sum_{i = 0}^{k} {k \brace i} \cdot i! \cdot C_n^i nk=i=0k{ik}i!Cni 等式左边是“ k k k 个不同的球放入 n n n 个不同的盒子,盒子可以为空的方案数”,右边即为枚举不为空的盒子数,分别计算,因此两边相等。
把组合数拆开可以得到: n k = ∑ i = 0 k { k i } ⋅ n i ‾ n^k = \sum_{i = 0}^{k} {k \brace i} \cdot n^{\underline i} nk=i=0k{ik}ni

考虑求 S k ( n ) S_k(n) Sk(n) 的递推式,用错位相减法:
S k ( n ) = ∑ i = 0 n − 1 a i i k ‾ a S k ( n ) = ∑ i = 1 n a i ( i − 1 ) k ‾ ⇒ ( 1 − a ) S k ( n ) = ∑ i = 1 n − 1 a i [ i k ‾ − ( i − 1 ) k ‾ ] + a 0 0 k ‾ − a n ( n − 1 ) k ‾ = ∑ i = 1 n a i [ i k ‾ − ( i − 1 ) k ‾ ] − a n n k ‾ + a n ( n − 1 ) k + a 0 0 k ‾ − a n ( n − 1 ) k = ∑ i = 1 n a i [ i k ‾ − ( i − 1 ) k ‾ ] − a n n k ‾ + a 0 0 k ‾ = ∑ i = 1 n a i ( i − 1 ) k − 1 ‾ [ i − ( i − k ) ] − a n n k ‾ + a 0 0 k ‾ = a k ∑ i = 0 n − 1 a i i k − 1 ‾ − a n n k ‾ + a 0 0 k ‾ = a k S k − 1 ( n ) − a n n k ‾ + a 0 0 k ‾ ⇒ S k ( n ) = a k 1 − a S k − 1 ( n ) − a n n k ‾ + a 0 0 k ‾ 1 − a \begin{aligned} S_k(n) &= \sum_{i = 0}^{n - 1} a^ii^{\underline k} \\ aS_k(n) &= \sum_{i = 1}^{n} a^i(i - 1)^{\underline k} \\ \Rightarrow (1 - a)S_k(n) &= \sum_{i = 1}^{n - 1} a^i \left[i^{\underline k} - (i - 1)^{\underline k}\right] + a^00^{\underline k} - a^n(n - 1)^{\underline k} \\ &= \sum_{i = 1}^n a^i \left[i^{\underline k} - (i - 1)^{\underline k}\right] - a^nn^{\underline k} + a^n(n - 1)^k + a^00^{\underline k} - a^n(n - 1)^k \\ &= \sum_{i = 1}^n a^i \left[i^{\underline k} - (i - 1)^{\underline k}\right] - a^nn^{\underline k} + a^00^{\underline k} \\ &= \sum_{i = 1}^n a^i (i - 1)^{\underline{k - 1}}[i - (i - k)] - a^nn^{\underline k} + a^00^{\underline k} \\ &= ak\sum_{i = 0}^{n - 1} a^i i^{\underline{k - 1}} - a^nn^{\underline k} + a^00^{\underline k} \\ &= akS_{k - 1}(n) - a^nn^{\underline k} + a^00^{\underline k} \\ \Rightarrow S_k(n) &= \frac{ak}{1 - a} S_{k - 1}(n) - \frac{a^nn^{\underline k} + a^00^{\underline k}}{1 - a} \end{aligned} Sk(n)aSk(n)(1a)Sk(n)Sk(n)=i=0n1aiik=i=1nai(i1)k=i=1n1ai[ik(i1)k]+a00kan(n1)k=i=1nai[ik(i1)k]annk+an(n1)k+a00kan(n1)k=i=1nai[ik(i1)k]annk+a00k=i=1nai(i1)k1[i(ik)]annk+a00k=aki=0n1aiik1annk+a00k=akSk1(n)annk+a00k=1aakSk1(n)1aannk+a00k 特别地, S 0 ( n ) = ∑ i = 0 n − 1 a i = 1 − a n 1 − a S_0(n) = \sum_{i = 0}^{n - 1} a^i = \frac{1 - a^n}{1 - a} S0(n)=i=0n1ai=1a1an。将 a a a 替换为 1 2 \frac{1}{2} 21 得到 S k ( n ) = { 2 ( 1 − 1 2 n ) k = 1 k S k − 1 ( n ) − n k ‾ 2 n − 1 k > 1 S_k(n) = \begin{cases} 2\left(1 - \dfrac{1}{2^n}\right) & k = 1 \\ k S_{k - 1}(n) - \dfrac{n^{\underline k}}{2^{n - 1}} & k > 1 \end{cases} Sk(n)=2(12n1)kSk1(n)2n1nkk=1k>1 这时候手刨几项:

  • S 0 ( n ) = 2 ( 1 − 1 2 n ) S_0(n) = 2(1 - \frac{1}{2^n}) S0(n)=2(12n1)
  • S 1 ( n ) = 1 ⋅ 2 ( 1 − 1 2 n ) − n 2 n − 1 S_1(n) = 1 \cdot 2(1 - \frac{1}{2^n}) - \frac{n}{2^{n - 1}} S1(n)=12(12n1)2n1n
  • S 2 ( n ) = 2 [ 1 ⋅ 2 ( 1 − 1 2 n ) − n 2 n − 1 ] − n ( n − 1 ) 2 n S_2(n) = 2\left[1 \cdot 2(1 - \frac{1}{2^n}) - \frac{n}{2^{n - 1}}\right] - \frac{n(n - 1)}{2^n} S2(n)=2[12(12n1)2n1n]2nn(n1)
  • S 3 ( n ) = 3 { 2 [ 1 ⋅ 2 ( 1 − 1 2 n ) − n 2 n − 1 ] − n ( n − 1 ) 2 n } − n ( n − 1 ) ( n − 2 ) 2 n S_3(n) = 3 \left\{2\left[1 \cdot 2(1 - \frac{1}{2^n}) - \frac{n}{2^{n - 1}}\right] - \frac{n(n - 1)}{2^n}\right\} - \frac{n(n - 1)(n - 2)}{2^n} S3(n)=3{2[12(12n1)2n1n]2nn(n1)}2nn(n1)(n2)

接下来就是神仙操作了,还记得常系数齐次线性递推么? 将常数项分成两部分,将含 n n n 的部分提出一个 1 2 n \frac{1}{2^n} 2n1 S 3 ( n ) = 3 { 2 [ 1 ⋅ 2 ( 1 − 1 2 n ) − n 2 n − 1 ] − n ( n − 1 ) 2 n } − n ( n − 1 ) ( n − 2 ) 2 n = 12 − 1 2 n [ 12 + 6 n + 3 n ( n − 1 ) + n ( n − 1 ) ( n − 2 ) ] \begin{aligned} S_3(n) &= 3 \left\{2\left[1 \cdot 2(1 - \frac{1}{2^n}) - \frac{n}{2^{n - 1}}\right] - \frac{n(n - 1)}{2^n}\right\} - \frac{n(n - 1)(n - 2)}{2^n} \\ &= 12 - \frac{1}{2^n}[12 + 6n + 3n(n - 1) + n(n - 1)(n- 2)] \end{aligned} S3(n)=3{2[12(12n1)2n1n]2nn(n1)}2nn(n1)(n2)=122n1[12+6n+3n(n1)+n(n1)(n2)] 两个 12 12 12 是一样的!其实原因就在于 S 0 ( n ) = 2 ( 1 − 1 2 n ) S_0(n) = 2(1 - \frac{1}{2^n}) S0(n)=2(12n1),两个 1 1 1 可以分给两边,使得新的一个 S k ( n ) S_k(n) Sk(n) 可以写成 S k ( n ) = G k ( 0 ) − G k ( n ) 2 n S_k(n) = G_k(0) - \frac{G_k(n)}{2^n} Sk(n)=Gk(0)2nGk(n) 其中 G k ( n ) G_k(n) Gk(n) 显然是一个 k k k 次多项式,而 G k ( 0 ) G_k(0) Gk(0) 正式它的常数项!

可能的疑问是,为什么不能直接提出一个 1 2 n \frac{1}{2^n} 2n1,变成 S k ( n ) = T k ( n ) 2 n S_k(n) = \frac{T_k(n)}{2^n} Sk(n)=2nTk(n) 原因是, S 0 ( n ) S_0(n) S0(n) 事实上是两部分,如果不分开的话, T k ( n ) T_k(n) Tk(n) 中会有 2 n 2^n 2n 这样的东西( S 0 ( n ) S_0(n) S0(n) 中的 “ 1 1 1”造成的),所以不可以直接提 1 2 n \frac{1}{2^n} 2n1。分开过后, G k ( n ) G_k(n) Gk(n) 就不含指数函数了!

回代进 F k ( n ) F_k(n) Fk(n) F k ( n ) = 2 n − 1 ∑ j = 0 k { k j } S j ( n ) + n k = 2 n − 1 ∑ j = 0 k { k j } ( G j ( 0 ) − G j ( n ) 2 n ) + n k = 2 n − 1 ( ∑ i = 0 k { k i } G i ( 0 ) − ∑ i = 0 k { k i } G i ( n ) 2 n ) + n k \begin{aligned} F_k(n) &= 2^{n - 1} \sum_{j = 0}^k {k \brace j} S_j(n) + n^k \\ &= 2^{n - 1} \sum_{j = 0}^k {k \brace j} \left(G_j(0) - \frac{G_j(n)}{2^n}\right) + n^k \\ &= 2^{n - 1} \left(\sum_{i = 0}^k {k \brace i} G_i(0) - \frac{\sum_{i = 0}^k {k \brace i} G_i(n)}{2^n}\right) + n^k \end{aligned} Fk(n)=2n1j=0k{jk}Sj(n)+nk=2n1j=0k{jk}(Gj(0)2nGj(n))+nk=2n1(i=0k{ik}Gi(0)2ni=0k{ik}Gi(n))+nk H k ( n ) = ∑ i = 0 k { k i } G i ( n ) H_k(n) = \sum_{i = 0}^k {k \brace i} G_i(n) Hk(n)=i=0k{ik}Gi(n) 显然 H i ( n ) H_i(n) Hi(n) k k k 次多项式,且 F k ( n ) = 2 n − 1 ( H k ( 0 ) − H k ( n ) 2 n ) + n k F_k(n) = 2^{n - 1}\left(H_k(0) - \frac{H_k(n)}{2^n}\right) + n^k Fk(n)=2n1(Hk(0)2nHk(n))+nk 接下来求出 R k ( n ) = H k ( 0 ) − 1 2 n H k ( n ) R_k(n) = H_k(0) - \frac{1}{2^n}H_k(n) Rk(n)=Hk(0)2n1Hk(n) 即可。

  • H k ( 0 ) H_k(0) Hk(0) 的部分:
    这个函数我们一项都算不出来,回顾一下开头,发现 R k ( n ) R_k(n) Rk(n) 可以算: R k ( n ) = ∑ i = 0 n − 1 i k 2 i R_k(n) = \sum_{i = 0}^{n - 1} \frac{i^k}{2^i} Rk(n)=i=0n12iik 把式子弄一下 H k ( n ) = 2 n H k ( 0 ) − 2 n R k ( n ) H_k(n) = 2^nH_k(0) - 2^nR_k(n) Hk(n)=2nHk(0)2nRk(n) 那么用一个二元组 { x , y } \{x, y\} {x,y} 表示 H k ( n ) H_k(n) Hk(n) H k ( n ) = x H k ( 0 ) − y H_k(n) = xH_k(0) - y Hk(n)=xHk(0)y,这个二元组显然可以快速地进行加、减和乘一个常的运算。有了这些我们就可以用 H k ( 0 ) , H k ( 1 ) , ⋯   , H k ( k ) H_k(0), H_k(1), \cdots, H_k(k) Hk(0),Hk(1),,Hk(k) 的二元表示插出 H k ( k + 1 ) H_k(k + 1) Hk(k+1) 的二元表示记为 { a 1 , b 1 } \{a_1,b_1\} {a1,b1} H k ( n ) = 2 n H k ( 0 ) − 2 n R k ( n ) H_k(n) = 2^nH_k(0) - 2^nR_k(n) Hk(n)=2nHk(0)2nRk(n) 也能得到一个 H k ( k + 1 ) H_k(k + 1) Hk(k+1) 的二元表示记为 { a 2 , b 2 } \{a_2, b_2\} {a2,b2}。由 H k ( k + 1 ) = H k ( k + 1 ) H_k(k + 1) = H_k(k + 1) Hk(k+1)=Hk(k+1) 得到 a 1 H k ( 0 ) − b 1 = a 2 H k ( 0 ) − b 2 a_1H_k(0) - b_1 = a_2H_k(0) - b_2 a1Hk(0)b1=a2Hk(0)b2 于是 H k ( 0 ) = b 1 − b 2 a 1 − a 2 H_k(0) = \frac{b_1 - b_2}{a_1 - a_2} Hk(0)=a1a2b1b2

    注意这两个二元表示是不等价的!可以理解为只要给出次数,拉格朗日插值就可以形式化地创造一个表示方法,这个新的值的计算方式与你原来计算点值的方式没有任何关系,因此这个方程有解。

  • H k ( n ) H_k(n) Hk(n) 的部分:
    得到 H k ( 0 ) H_k(0) Hk(0),就知道了 H k ( 1 ) , H k ( 2 ) , ⋯   , H k ( k ) H_k(1), H_k(2), \cdots, H_k(k) Hk(1),Hk(2),,Hk(k),直接拉格朗日插值即可。


还有一个细节是算 2 n 2^n 2n 什么的, n n n 有一百万位显然不能快速幂……要用欧拉定理: a φ ( p ) ≡ 1   ( mod  p ) a^{\varphi(p)} \equiv 1 \ (\text{mod} \ p) aφ(p)1 (mod p) 这里 p = 1 0 9 + 7 p = 10^9 + 7 p=109+7 是个质数,所以 φ ( p ) = p − 1 \varphi(p) = p - 1 φ(p)=p1,所以 2 n ≡ 2 n  mod  ( p − 1 )   ( mod  p ) 2^n \equiv 2^{n \ \text{mod} \ (p - 1)} \ (\text{mod} \ p) 2n2n mod (p1) (mod p)


做完了。这题太夸张了。据说 高阶差分 可以简单一点点,或者最开始就往 常系数线性递推 化。太菜了看不怎么懂……

代码

变量名有出入,但思路是完全一致的。

#include <algorithm>
#include <cstdio>
#include <cstring>

typedef std::pair<int, int> PII;

const int MAXN = 1000000;
const int MOD = 1000000007;
const int PHI = MOD - 1;

inline int Add(int x, const int &y) {
	x += y; if (x >= MOD) x -= MOD; return x;
}

inline int Sub(int x, const int &y) {
	x -= y; if (x < 0) x += MOD; return x;
}

inline int Mul(const int &x, const int &y) {
	return (long long)x * y % MOD;
}

int Pow(int x, int y) {
	int ret = 1;
	while (y) {
		if (y & 1)
			ret = Mul(ret, x);
		y >>= 1;
		x = Mul(x, x);
	}
	return ret;
}

const int INV2 = Pow(2, MOD - 2);

PII operator + (const PII &x, const PII &y) {
	return std::make_pair(Add(x.first, y.first), Add(x.second, y.second));
}

PII operator - (const PII &x, const PII &y) {
	return std::make_pair(Sub(x.first, y.first), Sub(x.second, y.second));
}

PII operator * (const PII &x, const int &y) {
	return std::make_pair(Mul(x.first, y), Mul(x.second, y));
}

int N, P, K;
int Fac[MAXN + 5], InvFac[MAXN + 5];

int H[MAXN + 5];
int F[MAXN + 5];
PII G[MAXN + 5];

int Pre[MAXN + 5], Suf[MAXN + 5];

void Init(int n) {
	Pre[0] = n;
	for (int i = 1; i <= K; i++)
		Pre[i] = Mul(Pre[i - 1], Sub(n, i));
	Suf[K + 1] = 1;
	for (int i = K; i >= 0; i--)
		Suf[i] = Mul(Suf[i + 1], Sub(n, i));
}

PII Lagrange1(int n) {
	Init(n);
	PII res(0, 0);
	for (int i = 0; i <= K; i++) {
		int A = Mul(i ? Pre[i - 1] : 1, Suf[i + 1]);
		int B = Mul(InvFac[i], InvFac[K - i]);
		PII C = G[i] * Mul(A, B);
		res = ((K - i) & 1) ? (res - C) : (res + C);
//		printf("%d %d (%d, %d)\n", A, B, res.first, res.second);
	}
	return res;
}

int Lagrange2(int n) {
	Init(n);
	int res = 0;
	for (int i = 0; i <= K; i++) {
		int A = Mul(i ? Pre[i - 1] : 1, Suf[i + 1]);
		int B = Mul(InvFac[i], InvFac[K - i]);
		int C = Mul(H[i], Mul(A, B));
		res = ((K - i) & 1) ? Sub(res, C) : Add(res, C);
	}
	return res;
}

int main() {
	char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9') {
		P = ((long long)P * 10 + c - '0') % PHI;
		N = ((long long)N * 10 + c - '0') % MOD;
		c = getchar();
	}
	scanf("%d", &K);

	Fac[0] = 1;
	for (int i = 1; i <= K; i++)
		Fac[i] = Mul(Fac[i - 1], i);
	InvFac[K] = Pow(Fac[K], MOD - 2);
	for (int i = K - 1; i >= 0; i--)
		InvFac[i] = Mul(InvFac[i + 1], i + 1);

	for (int i = 1; i <= K + 1; i++)
		F[i] = Add(F[i - 1], Mul(Pow(INV2, i - 1), Pow(i - 1, K)));
	for (int i = 0; i <= K + 1; i++)
		G[i] = std::make_pair(Pow(2, i), Mul(Pow(2, i), F[i]));

	PII x = G[K + 1], y = Lagrange1(K + 1);
	int A = Sub(y.second, x.second);
	int B = Sub(x.first, y.first);
	H[0] = Mul(A, Pow(B, MOD - 2));
	for (int i = 1; i <= K; i++)
		H[i] = Add(Mul(G[i].first, H[0]), G[i].second);

	int Ans = Sub(Mul(Lagrange2(N), Pow(INV2, P)), H[0]);
	Ans = Add(Mul(Pow(2, P ? (P - 1) : (MOD - 2)), Ans), Pow(N, K));
	printf("%d", Ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值