題解 一道數學題 加強版
題目大意
給出一個二元函式,滿足:
\[f(k,x)=\begin{cases} 1&x=1\\ \sum_{i=1}^{x-1}f(k,i)+x^k&x>1 \end{cases}\]
給出\(n,k\),求出\(f(k,n)\)。
\(n\le 10^{10^6},k\le 10^6\)
思路
借鑑了Master.Yi的思路(但是他裡面有個式子似乎寫錯了)
我們首先可以得到轉移式:
\[f(k,x)-(f(k,x-1)-(x-1)^k)=f(k,x-1)+x^k \]
\[\Rightarrow f(k,x)=2f(k,x-1)-(x-1)^k+x^k \]
我們發現直接求似乎不是很好求,我們構造一個新函式\(g(k,x)\)
\[f(k,x)+g(k,x)=2(f(k,x-1)+g(k,x-1)) \]
\[\Rightarrow g(k,x)=2g(k,x-1)+(x-1)^k-x^k \]
我們於是發現我們可以把\(g(k,x)\)用\(g(k,0)\)的形式表示。而我們又發現\(g(k,x)\)其實是關於\(x\)的\(k-1\)次多項式,於是得到:
\[\sum_{i=0}^{k} \binom{k}{i}(-1)^ig(k,i)=0 \]
證明可以用組合數問題裡推出的式子,這個其實就是\(x=-1\)的情況,容易看出和式為\(0\)。(其實對於任何小於\(k\)次的多項式這都是成立的)
於是,我們就可以通過設立方程解出\(g(k,0)\)
而我們觀察到最終的答案\(f(k,x)=2^{x-1}(f(k,1)+g(k,1))-g(k,x)\),於是,我們的目標就是求出\(g(k,x)\)。又因為我們點值是連續的,所以我們可以\(\Theta(k)\)拉格朗日插值法求出\(g(k,x)\)。
綜上,我們的時間複雜度為\(\Theta(k)\)。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 1000000007 #define int long long #define MAXN 1000005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod; return res; } int n,k,np,cnt,pw[MAXN],vis[MAXN],fac[MAXN],suf[MAXN],ifac[MAXN],prime[MAXN]; void Prepare (int up){ pw[1] = 1; for (Int i = 2;i <= up;++ i){ if (!vis[i]) prime[++ cnt] = i,pw[i] = qkpow (i,k); for (Int j = 1;j <= cnt && i * prime[j] <= up;++ j){ vis[i * prime[j]] = 1; pw[i * prime[j]] = 1ll * pw[i] * pw[prime[j]] % mod; if (i % prime[j] == 0) break; } } fac[0] = 1; for (Int i = 1;i <= up;++ i) fac[i] = 1ll * fac[i - 1] * i % mod; ifac[up] = qkpow (fac[up],mod - 2);for (Int i = up;i;-- i) ifac[i - 1] = 1ll * ifac[i] * i % mod; } signed main(){ char c;while (!isdigit (c = getchar())); for (n = np = c - '0';isdigit (c = getchar());n = (10ll * n + c - '0') % mod,np = (10ll * np + c - '0') % (mod - 1)); read (k),Prepare (k); int A = 1,B = 0,SA = 0,SB = 0; for (Int i = 0;i <= k;++ i){ int x = 1ll * (i & 1 ? -1 : 1) * fac[k] * ifac[i] % mod * ifac[k - i] % mod; SA = (SA + 1ll * A * x % mod) % mod,SB = (SB + 1ll * B * x % mod) % mod; A = A * 2 % mod,B = (B * 2 % mod + mod - pw[i + 1] + pw[i]) % mod; } int g = -1ll * SB * qkpow (SA,mod - 2) % mod,ans = 1ll * qkpow (2,np - 1) * 2 * g % mod; suf[k] = 1;for (Int i = k - 1;~i;-- i) suf[i] = 1ll * suf[i + 1] * (n - i) % mod; for (Int i = 0,pre = 1;i < k;++ i){ ans = (ans - 1ll * g * pre % mod * suf[i + 1] % mod * ifac[i] % mod * ifac[k - 1 - i] % mod * (k - i & 1 ? 1 : -1)) % mod; pre = 1ll * pre * (n - i) % mod,g = (2 * g % mod - pw[i + 1] + pw[i]) % mod; } write ((ans % mod + mod) % mod),putchar ('\n'); return 0; }