题目传送门
\(AC\) 的第一道黑题,写个题解纪念一下。
题目大意
有三种基因,第一种是可以随便填的,第二种是只能填奇数次的,第三种是只能填偶数次。
思路
容易想到这是一道指数型生成函数 \((EGF)\),解释一下什么是 \(EGF\):
对于这道题,对于第一种基因,对应的数列为 \(<1,1,1,1,...>\),即为:
对于第二种基因,对应的数列为 \(<1,0,1,0,...>\),即为:
解释一下:
对于第三种基因,对应的数列为 \(<0,1,0,1,...>\),即为 \(G(x)=\dfrac{e^x-e^{-x}}{2}\)。同理:
把上面三个式子全部乘一起,再加一个四次方,也就是:
第 \(n\) 次项的系数乘上 \(n!\) 就是答案,为什么呢?
证明
这需要解释一下 \(EGF\) 的工作原理,因为 \(EGF\) 是形如:
而 \(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!\) 就是答案了。那么对于原式,我们进行暴力展开:
答案也就是化简和结果的 \(n\) 次项系数乘上 \(n!\)
因为 \(-4\) 是常数项,所以我们不需要。那么把这个式子乘上 \(n!\)。得到:
注意事项
接下来就是愉快的敲代码了,要注意因为要算负数的幂,所以在快速幂里面记得 \(+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;
}
完结撒花