题解 一道数学题 加强版
题目大意
给出一个二元函数,满足:
\[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)\),从而求出\(g(k,1\to k)\)。
而我们观察到最终的答案\(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;
}