[LOJ6671]EntropyIncreaser 与 Minecraft

壹、题目描述 ¶

传送门 to LOJ.

贰、题解 ¶

每一维都是一样的,不难看出每一维的生成函数为

\[-1+\sum_{i=0}^\infty 2x^i={1+x\over 1-x} \]

那么,总方案数的生成函数为

\[\left({1+x\over 1-x}\right)^n \]

由于我们想要求前缀和,所以再卷上一个 \({1\over 1-x}\),得到

\[F(n)={(1+x)^n\over (1-x)^{n+1}} \]

试图将其泰勒展开,不难得到前几项为

\[\begin{matrix} &1 \\ &1&2n \\ &2&4n&4n^2 \\ &6&16n&12n^2&8n^3 \\ &24&64n&80n^2&32n^3&16n^4 \\ &120&368n&400n^2&320n^3&80n^4&32n^5 \end{matrix} \]

使用 \((2n+1)^k\) 显然是可以拟合的,但是还需要补上一些项,不难发现最后的递推式为

\[f_i=(2n+1)f_{i-1}+(i-1)^2f_{i-2} \]

但是需要注意的是,这个递推式忽略了泰勒展开的 \(i!\),所以最后还要除以 \(i!\).

时间复杂度 \(\mathcal O(p)\).


\(\mathrm{update\;on\;2021/10/22}\):突然发现的确不用展开,展开是不必要的,我们考虑 \(F(n)=(1+x)^n(1-x)^{-(n+1)}\) 的高阶导数:

\[F'(n)=n(1+x)^{n-1}(1-x)^{-n+1}+(n+1)(1-x)^{-n-2}(1-x)^n \\ \cdots \]

然后不难发现,事实上:

\[\begin{aligned}{} [x^m]F(n)&=\sum_{i=0}^m{m\choose i}n^{\underline i}\cdot (n+1)^{\overline {m-i}} \\ &=\sum_{i=0}^m{n\choose i}{n+m-i\choose m-i}m! \end{aligned} \]

后面那个 \(m!\) 就是泰勒展开被除掉的东西,也就是说,其实 \(f_m=\sum_{i=0}^m{n\choose i}{n+m-i\choose m-i}\),至于为什么存在该递推式,还真不得知。先写一点后面的推倒(可能错了?)

\[\begin{aligned}{} f_i&=(2n+1)f_{i-1}+(i-1)^2f_{i-2} \\ g_i&=\frac{2n+1}{i}g_{i-1}+\frac{i-1}{i}g_{i-2} \\ g'&=(2n+1)gx+g'\cdot x^3 \end{aligned} \]

其实是想倒着推回去而已,不过我又不会了

叁、参考代码 ¶

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;

#define NDUBUG
#include<cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    // #define int long long
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int Mod=1e9+7;
const int maxn=1e6;
const int maxp=1e6;

int f[maxn+5], n, p;

inline int qkpow(int a, int n){
	int ret=1;
	for(; n>0; n>>=1, a=1ll*a*a%Mod)
		if(n&1) ret=1ll*ret*a%Mod;
	return ret;
}

signed main(){
	n=readin(1), p=readin(1);
	f[0]=1, f[1]=2*n+1;
	for(int i=2; i<=p; ++i)
		f[i]=(1ll*(2*n+1)*f[i-1]%Mod+1ll*(i-1)*(i-1)%Mod*f[i-2]%Mod)%Mod;
	int fac=1;
	for(int i=1; i<=p; ++i) fac=1ll*fac*i%Mod;
	writc(1ll*f[p]*qkpow(fac, Mod-2)%Mod);
    return 0;
}

肆、关键之处 ¶

生成函数总是多维度分开考虑,然后暴力卷起来......当然,前提是这几维互不相关。

posted @ 2021-07-28 20:42  Arextre  阅读(71)  评论(0编辑  收藏  举报