JZOJ6828. 【2020.10.25提高组模拟】幂

15 篇文章 0 订阅
6 篇文章 0 订阅

Description

  • 在这里插入图片描述

  • T T T组数据, T ≤ 1 e 5 , n ≤ 1 e 7 T\le1e5,n\le1e7 T1e5,n1e7

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)=2x1x12x3x2

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)=2x12x3x2 1x1

  • 关于 F ( x ) F(x) F(x)的求根公式为什么是负号,考虑后面的东西开根是 1 − x + . . . 1-x+... 1x+...,而 F ( x ) F(x) F(x)没有负数次幂,因此分子部分常数项和一次项都被消掉了,所以要是负号(直接计算用洛必达法则计算极限也可以证明?)

  • 那么问题在于求 ( 1 − 2 x − 3 x 2 ) − 0.5 (1-2x-3x^2)^{-0.5} (12x3x2)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)ansn3nansn1(n+3)ansn2+(3n6)ansn3=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);
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值