[题解] Codeforces 1548 C The Three Little Pigs 组合数学,生成函数
题目
首先令\(x=i\)时的答案为\(f_i\) ,令\(f_i\)对应的普通生成函数为\(F(x)\)。
很容易发现\(F(x)=\sum_{i=0}^n (1+x)^{3i}\),sigma是在枚举第几轮吃(i=0也枚举了,不影响答案), \((1+x)^{3i}\)是在枚举\(3i\)只猪里哪些会被吃。
用等比数列求和公式求出\(F(x)=\frac{(1+x)^{3n+3}-1}{(1+x)^3-1}\)。
\(F(x)\)的分子可以用二项式定理暴力展开,分母展开是\(x^3+3x^2+3x\)。由于\(F(x)\)没有无限项,所以暴力做多项式除法是可以除尽的。所以现在就是要暴力计算一个\(3n+3\)次多项式除以一个3次多项式的值,具体做法是从\(3n\)到0枚举每一个次数,然后决定这一项的系数。同时记录当前商和除数的积,则第i位的系数=\((1+x)^{3n+3}-1\)第i+3位的系数-当前商第i位的系数。然后对于询问每次直接输出就行了。时间复杂度\(O(n)\)。
点击查看代码
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <LL,LL>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
using namespace std;
const LL MOD=1e9+7;
LL qpow(LL x,LL a)
{
LL res=x,ret=1;
while(a>0)
{
if((a&1)==1) ret=ret*res%MOD;
a>>=1;
res=res*res%MOD;
}
return ret;
}
LL n,q,fac[3000100],inv[3000100],ans[3000100],coef[3000100],cur[3000100];
LL C(LL nn,LL mm){return fac[nn]*inv[mm]%MOD*inv[nn-mm]%MOD;}
int main()
{
fac[0]=1;repn(i,3000095) fac[i]=fac[i-1]*(LL)i%MOD;
inv[3000085]=qpow(fac[3000085],MOD-2);
for(LL i=3000084;i>=0;--i) inv[i]=inv[i+1]*(i+1)%MOD;
cin>>n;
rep(i,n*3+4) coef[i]=C(n*3+3,i);
--coef[0];
int hi=n*3+3;
for(int i=hi-3;i>=0;--i)
{
LL need=(coef[i+3]-cur[i+3]+MOD)%MOD;
ans[i]=need;
(cur[i+3]+=need)%=MOD;
(cur[i+2]+=need*3LL)%=MOD;
(cur[i+1]+=need*3LL)%=MOD;
}
cin>>q;
LL x;
rep(qn,q)
{
scanf("%lld",&x);
printf("%lld\n",ans[x]);
}
return 0;
}