题解:P2012 拯救世界2

题目传送门

\(AC\) 的第一道黑题,写个题解纪念一下。

题目大意

有三种基因,第一种是可以随便填的,第二种是只能填奇数次的,第三种是只能填偶数次。

思路

容易想到这是一道指数型生成函数 \((EGF)\),解释一下什么是 \(EGF\)

\[F(x)=\sum_{i=0}^\infty f_i\frac{x^i}{i!} \]

对于这道题,对于第一种基因,对应的数列为 \(<1,1,1,1,...>\),即为:

\[F(x)=e^x \]

对于第二种基因,对应的数列为 \(<1,0,1,0,...>\),即为:

\[R(x)=\dfrac{e^x+e^{-x}}{2} \]

解释一下:

\[e^x=1+x+\dfrac{x^2}{2!}+\dfrac{x^3}{3!}+... \]

\[e^{-x}=1-x+\dfrac{x^2}{2!}-\dfrac{x^3}{3!}+... \]

\[\dfrac{e^x+e^{-x}}{2}=1+\dfrac{x^2}{2!}+\dfrac{x^4}{4!}+... \]

对于第三种基因,对应的数列为 \(<0,1,0,1,...>\),即为 \(G(x)=\dfrac{e^x-e^{-x}}{2}\)。同理:

\[\dfrac{e^x-e^{-x}}{2}=x+\dfrac{x^3}{3!}+\dfrac{x^5}{5!}+... \]

把上面三个式子全部乘一起,再加一个四次方,也就是:

\[(e^x\times\dfrac{e^x+e^{-x}}{2}\times\dfrac{e^x-e^{-x}}{2})^4 \]

\(n\) 次项的系数乘上 \(n!\) 就是答案,为什么呢?

证明

这需要解释一下 \(EGF\) 的工作原理,因为 \(EGF\) 是形如:

\[F(x)=\sum_{i=0}^\infty f_i\dfrac{x^i}{i!} \]

\(fi\) 就是序列长度为 \(n\) 时的排列数。我们用一个简单的例子解释一下:\(a\times x^b\) 定义为序列长度为 \(b\) 时的组合数为 \(a\)。那么对于长度为 \(b_1\)\(b_2\) 的序列,分别有 \(a_1\)\(a_2\) 种组合数,那么对于长度为 \(b_1+b_2\) 的序列,就有 \(a_1\times a_2\) 种组合数,即为 \(a_1\times a_2\times x^{b_1+b_2}\)。而且 \(a=\dfrac{f_i}{i!}\),这个是因为排列数是要算顺序的,而组合数不用。这也就解释了为什么系数乘上 \(i!\) 就是答案。那么我们只需要把得到的式子全部乘一起,再求第 \(n\) 次项的系数乘 \(n!\) 就可以了

化简

现在我们明白了为什么系数乘上 \(i!\) 就是答案了。那么对于原式,我们进行暴力展开:

\[(e^x\times\dfrac{e^x+e^{-x}}{2}\times\dfrac{e^x-e^{-x}}{2})^4 \]

\[=(\dfrac{1}{4}(e^{3x}-e^{-x}))^4 \]

\[=\dfrac{1}{256}(e^{12x}-4e^{8x}+6e^{4x}-4+e^{-4x}) \]

答案也就是化简和结果的 \(n\) 次项系数乘上 \(n!\)

\[=\dfrac{1}{256}(\sum\dfrac{(12e)^i}{i!}-\sum\dfrac{4*(8e)^i}{i!}+\sum\dfrac{6*(4e)^i}{i!}+\sum\dfrac{(-4e)^i}{i!}-4) \]

因为 \(-4\) 是常数项,所以我们不需要。那么把这个式子乘上 \(n!\)。得到:

\[=\dfrac{1}{256}((12e)^n-4*(8e)^n+6*(4e)^n+(-4e)^n) \]

\[=81\times12^{n−4}−4\times8^{n−2}+6\times4^{n−4}+(−4)^{n−4} \]

注意事项

接下来就是愉快的敲代码了,要注意因为要算负数的幂,所以在快速幂里面记得 \(+mod\) 后再模 \(mod\)

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1010101;
const int mod=1e9;
ll n,ans;
ll qpow(ll x,ll y){
	ll sum=1;
	while(y){
		if(y&1)sum=(sum*x+mod)%mod;
		x=(x*x+mod)%mod;
		y>>=1;
	}
	return (sum+mod)%mod;
}
int main(){
	while(1){
		scanf("%lld",&n);
		if(!n)break;
		if(n<=3){
			printf("0\n");
			continue;
		}
		ans=0;
		ans=(ans+81*qpow(12,n-4)%mod)%mod;
		ans=(ans-qpow(8,n-2)%mod+mod)%mod;
		ans=(ans+6*qpow(4,n-4)%mod)%mod;
		ans=(ans+qpow(-4,n-4)%mod+mod)%mod;
		printf("%lld\n",(ans+mod)%mod);
	}
	return 0;
}

完结撒花

posted @ 2025-09-10 21:40  一班的hoko  阅读(13)  评论(0)    收藏  举报