Description
-
T T T组数据, T ≤ 1 e 5 , n ≤ 1 e 7 T\le1e5,n\le1e7 T≤1e5,n≤1e7
Solution
- 好家伙,最下面的数据范围居然是这样的:
- 直接以为卡特兰数乘上个组合数就能切了(
- 然而数据范围在读入的地方
-
这个看起来 1 e 7 1e7 1e7的 O ( 1 ) O(1) O(1)查询多半是递推吧。
-
因此写出dp, f ( n ) , g ( n ) f(n),g(n) f(n),g(n)分别表示长度为 n n n合法方案数以及贡献和。
-
讨论第一个是 ′ x ′ 'x' ′x′还是 ′ ( ′ '(' ′(′,容易得到转移,以及对应的生成函数:
F ( x ) = 1 + x F ( x ) + x 2 F 2 ( x ) F(x)=1+xF(x)+x^2F^2(x) F(x)=1+xF(x)+x2F2(x)G ( x ) = x F ( x ) + x G ( x ) + 2 x 2 G ( x ) F ( x ) G(x)=xF(x)+xG(x)+2x^2G(x)F(x) G(x)=xF(x)+xG(x)+2x2G(x)F(x)
-
暴力解:
F ( x ) = 1 − x − 1 − 2 x − 3 x 2 2 x F(x)=\frac{1-x-\sqrt{1-2x-3x^2}}{2x} F(x)=2x1−x−1−2x−3x2
G ( x ) = 1 − x 1 − 2 x − 3 x 2 − 1 2 x G(x)=\frac{\frac{1-x}{\sqrt{1-2x-3x^2}}-1}{2x} G(x)=2x1−2x−3x21−x−1
-
关于 F ( x ) F(x) F(x)的求根公式为什么是负号,考虑后面的东西开根是 1 − x + . . . 1-x+... 1−x+...,而 F ( x ) F(x) F(x)没有负数次幂,因此分子部分常数项和一次项都被消掉了,所以要是负号(直接计算用洛必达法则计算极限也可以证明?)
-
那么问题在于求 ( 1 − 2 x − 3 x 2 ) − 0.5 (1-2x-3x^2)^{-0.5} (1−2x−3x2)−0.5,剩下的都可以线性变换。
-
套用短多项式求幂的方法:
-
F ( x ) = G k ( x ) F(x)=G^k(x) F(x)=Gk(x), l n F ( x ) = k l n G ( x ) ln\ F(x)=k\ ln\ G(x) ln F(x)=k ln G(x)
-
求导得
F ′ ( x ) F ( x ) = k G ′ ( x ) G ( x ) \frac{F'(x)}{F(x)}=k\frac{G'(x)}{G(x)} F(x)F′(x)=kG(x)G′(x)F ′ ( x ) G ( x ) = k G ′ ( x ) F ( x ) F'(x)G(x)=kG'(x)F(x) F′(x)G(x)=kG′(x)F(x)
-
那么考虑第 n n n项的系数,左边右边分别卷在一起,但是左边由于求了导数,所以涉及到了 f ( n + 1 ) f(n+1) f(n+1),又由于 G ( x ) G(x) G(x)是常数项的,所以系数相当于 O ( 1 ) O(1) O(1)算出,可以从 f ( 1.. n ) f(1..n) f(1..n)推到 f ( n + 1 ) f(n+1) f(n+1)。
-
最后是常数项,一般根据题意猜出?这题由于是在整数域内开根号,常数项应该是正负1吧。
-
-
可以化简为:
( n + 1 ) a n s n − 3 n ∗ a n s n − 1 − ( n + 3 ) a n s n − 2 + ( 3 n − 6 ) a n s n − 3 = 0 (n+1)ans_n-3n*ans_{n-1}-(n+3)ans_{n-2}+(3n-6)ans_{n-3}=0 (n+1)ansn−3n∗ansn−1−(n+3)ansn−2+(3n−6)ansn−3=0
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 10000005
#define ll long long
#define mo 998244353
using namespace std;
int T,n,i,j,k;
ll f[maxn],inv[maxn];
int main(){
freopen("ceshi.in","r",stdin);
// freopen("power.in","r",stdin);
// freopen("power.out","w",stdout);
inv[0]=inv[1]=1;
for(i=2;i<maxn;i++) inv[i]=inv[mo%i]*(mo-mo/i)%mo;
f[1]=1,f[2]=2;
for(i=3;i<maxn-1;i++) f[i]=(f[i-1]*3*i+f[i-2]*(i+3)+f[i-3]*(6-3*i))%mo*inv[i+1]%mo;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
printf("%lld\n",(f[n]+mo)%mo);
}
}