Live2D

题解 一道数学题 加强版

题目传送门

题目大意

给出一个二元函数,满足:

\[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;
}
posted @ 2020-07-22 16:48  Dark_Romance  阅读(128)  评论(0编辑  收藏  举报