各類求自然數冪和方法
高斯消元
我們知道:
\[\sum_{i=1}^{n}i=\frac{n(n+1)}{2}\]
以及:
\[\sum_{i=1}^{n}i^2=\frac{n(n+1)(2n+1)}{6}\]
以及:
\[\sum_{i=1}^{n}i^3=(\sum_{i=1}^{n}i)^2=(\frac{n(n+1)}{2})^2\]
那我們可以猜想,自然數的\(k\)次冪和對應的公式是一個次數為\(k+1\)的沒有常數項的多項式(實際上也是的)。
證明嗎,暫時不會。。。
However,我們可以拿這個猜想做題。
設這個\(k+1\)次的多項式\(f(x)=\sum_{i=1}^{k+1}a_ix^i\)
利用待定系數法,我們只需要知道\(k+2\)對\((x,f(x))\),列出方程組就能解出所有的\(a_i\),從而就能代入更大的\(x\)求出\(f(x)\)。
由於解方程組需要用到高斯消元算法,時間復雜度是\(O(k^3)\),在\(k\leq 100\)的範圍內還是能無壓力解決的。
總結
時間復雜度:\(O(k^3)\)
空間復雜度:\(O(k^2)\)
由於高斯消元時要在模意義下做除法,對於模數不是質數的情況無法適應,而且時間復雜度難以接受,不是一種較常用的方法。
第二類斯特林數
分析
定義\(S(n,m)\)表示\(n\)個有差別的球放入m個無差別的盒子中的方案數,要求盒子不能為空。
容易得到下面的遞推式:
考慮新加入的球,要麽放在新的盒子裏,要麽放在之前的盒子裏。因為球是有差別的,所以放在任意一個盒子裏的方案都是不一樣的,因此\(S(n-1,m)\)要乘上一個\(m\)。
要用它解決自然數冪和問題,還是要用到第二類斯特林數的一個性質:
\[a^k=\sum_{i=0}^{k}S(k,i)i!C_a^i\]
這個性質還是很好解釋的,我們可以把\(a^k\)當做\(k\)個有差別的球,放入\(a\)個有差別的盒子的方案數,盒子可以為空。
那麽我們就枚舉\(i\)個盒子被放滿了,\(S(k,i)\)只保證了球有差別,乘以\(i!\)相當於給盒子編號,令盒子也有差別
那麽就可以開始化自然數冪求和的式子:
\(\sum_{a=1}^{n}a^k\)
\(=\sum_{a=1}^{n}\sum_{i=0}^{k}S(k,i)i!C_a^i\)
兩個sigma沒有關聯,我們可以交換枚舉順序:
\(=\sum_{i=0}^{k}S(k,i)i!\sum_{a=1}^{n}C_a^i\)
由於\(a<i\)時\(C_a^{i}=0\),又可以化成:
\(=\sum_{i=0}^{k}S(k,i)i!\sum_{a=i}^{n}C_a^i\)
繼續化簡需要用到一個性質:
\(\sum_{a=i}^{n}C_a^i=C_{n+1}^{i+1}\)
證明考慮運用組合數遞推公式即:
\(C_i^j=C_{i-1}^j+C_{i-1}^{j-1}\)
\(C_{n+1}^{i+1}\)
\(=C_n^i+C_n^{i+1}\)
\(=C_n^i+C_{n-1}^i+C_{n-1}^{i+1}\)
\(=C_n^i+C_{n-1}^i+C_{n-2}^i+C_{n-2}^{i+1}\)
繼續化下去就會得到:
\(=\sum_{a=i}^{n}C_a^i\)
性質就得證了,上面的式子就化簡為:
\(=\sum_{i=0}^{k}S(k,i)i!C_{n+1}^{i+1}\)
組合數有點麻煩,我們展開為階乘形式:
\(=\sum_{i=0}^{k}S(k,i)i!\frac{(n+1)!}{(i+1)!(n-i)!}\)
拆開\((i+1)!=i!*(i+1)\):
\(=\sum_{i=0}^{k}S(k,i)\frac{(n+1)!}{(i+1)(n-i)!}\)
發現\(\frac{(n+1)!}{(n-i)!}\)其實是\(i+1\)個連續整數相乘,其中必有一個是\(i+1\)的倍數,因此式子一定取整數,就不用考慮模數的問題了。
那麽直接枚舉這\(i+1\)個連續的整數,得到了時間復雜度為\(O(k^2)\)的算法。計算斯特林數和求自然數冪的復雜度都是\(O(k^2)\),總復雜度就是\(O(k^2)\)。
Code
附帶分解乘法黑科技
#include <cstdio>
#include <cstring>
typedef long long ll;
const int N = 2007;
ll k, n, p, s[N][N];
ll multi(ll a, ll b)
{
ll x1 = a / 1000000, x2 = a % 1000000, y1 = b / 1000000, y2 = b % 1000000;
return (x1 * 1000000 % p * y1 % p * 1000000 % p + x1 * 1000000 % p * y2 % p + y1 * 1000000 % p * x2 % p + x2 * y2 % p) % p;
}
ll solve(ll n)
{
if (n == 0) return 0;
ll ret = 0;
for (int i = 1; i <= k && i <= n; i++)
{
ll sum = s[k][i];
for (ll j = n - i + 1; j <= n + 1; j++)
if (j % (i + 1) == 0) sum = multi(sum, j / (i + 1));
else sum = multi(sum, j);
ret = (ret + sum) % p;
}
return ret;
}
int main()
{
scanf("%lld%lld%lld%lld", &k, &n, &p);
s[0][0] = 1;
for (int i = 1; i <= k; i++)
for (int j = 1; j <= i; j++)
s[i][j] = (s[i - 1][j - 1] + multi(j, s[i - 1][j])) % p;
printf("%lld\n", solve(n) % p);
return 0;
}
總結
時間復雜度:\(O(k^2)\)
空間復雜度:\(O(k^2)\)
這種做法由於不用除法而適用於模數為任意數的情況,但是求斯特林數復雜度是\(O(k^2)\)的,當\(k\)較大時不再適用。
拉格朗日插值法
大坑待填。。。。
各類求自然數冪和方法