1 条题解
-
0
自动搬运
来自洛谷,原作者为

NaCly_Fish
北海虽赊,扶摇可接。搬运于
2025-08-24 22:53:51,当前版本为作者最后更新于2023-12-26 19:11:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
一看这题,我啪的一下就点进来了,很快啊!
设 是题面代码中序列 的生成函数,那么发现每次操作其实就是
也就是说答案(设 )
这是经典问题,可以做到 的时间复杂度。
啊好像还需要一些常数优化,那就展开解释一下吧。首先套用模板,设 为 的复合逆,即
答案就是
$$s_t=[x^0] \frac{F(x)}{(x-ax^2)^t}=[x^t]F(h(x)) \frac{xh'(x)}{h(x)} $$虽然 微分有限,但是在最后还需要一次卷积。反正 是给定的,没什么特殊性质,不如考虑把这部分揉进 里面去。根据代数方程的性质可知
$$h'(x)=\frac{1-2a h(x)}{1-4ax} \ , \ \frac{x}{h(x)}=1-ah(x) $$然后设 ,这样处理起来就比较方便了:
实际上,接下来的处理也很经典:
$$\hat F(h(x))=\hat F\left(\frac{1-x}{2a}\right) \circ \sqrt{1-4ax} $$设 ,然后将其分解为 ,就有 。
最后的做法似乎比出题人的常数稍大一点,但似乎容易处理一些。
update:好像实现效果比出题人还快了近一倍,很神秘。我的 DFT 部分也没有做精细的优化,补一下代码吧。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define N 2097158 #define ll long long #define p 998244353 using namespace std; inline void read(int &x){ x = 0; char c = getchar(); while(c<'0'||c>'9') c = getchar(); while(c>='0'&&c<='9'){ x = (x<<3)+(x<<1)+(c^48); c = getchar(); } } inline int power(int a,int t){ int res = 1; while(t){ if(t&1) res = (ll)res*a%p; a = (ll)a*a%p; t >>= 1; } return res; } int rt[N],rev[N],fac[N],ifac[N]; int siz; void init(int n){ int w,lim = 1; while(lim<=n) lim <<= 1,++siz; for(int i=1;i!=lim;++i) rev[i] = (rev[i>>1]>>1)|((i&1)<<(siz-1)); w = power(3,(p-1)>>siz); fac[0] = fac[1] = ifac[0] = ifac[1] = rt[lim>>1] = 1; for(int i=lim>>1|1;i!=lim;++i) rt[i] = (ll)rt[i-1]*w%p; for(int i=(lim>>1)-1;i;--i) rt[i] = rt[i<<1]; for(int i=2;i<=n;++i) fac[i] = (ll)fac[i-1]*i%p; ifac[n] = power(fac[n],p-2); for(int i=n-1;i;--i) ifac[i] = (ll)ifac[i+1]*(i+1)%p; } inline void dft(int *f,int lim){ static unsigned long long a[N]; int x,shift = siz-__builtin_ctz(lim); for(int i=0;i!=lim;++i) a[rev[i]>>shift] = f[i]; for(int mid=1;mid!=lim;mid<<=1) for(int j=0;j!=lim;j+=(mid<<1)) for(int k=0;k!=mid;++k){ x = a[j|k|mid]*rt[mid|k]%p; a[j|k|mid] = a[j|k]+p-x; a[j|k] += x; } for(int i=0;i!=lim;++i) f[i] = a[i]%p; } inline void idft(int *f,int lim){ reverse(f+1,f+lim); dft(f,lim); int x = p-((p-1)>>__builtin_ctz(lim)); for(int i=0;i!=lim;++i) f[i] = (ll)f[i]*x%p; } inline int getlen(int n){ return 1<<(32-__builtin_clz(n)); } inline void composite(const int *f,int n,int c,int *R){ static int g[N],h[N]; g[0] = 1,h[0] = f[0]; for(int i=1;i<=n;++i){ g[i] = (ll)g[i-1]*c%p; h[i] = (ll)f[i]*fac[i]%p; } for(int i=2;i<=n;++i) g[i] = (ll)g[i]*ifac[i]%p; reverse(g,g+n+1); int lim = getlen(n<<1); memset(g+n+1,0,(lim-n)<<2); memset(h+n+1,0,(lim-n)<<2); dft(g,lim),dft(h,lim); for(int i=0;i!=lim;++i) g[i] = (ll)g[i]*h[i]%p; idft(g,lim); for(int i=0;i<=n;++i) R[i] = (ll)g[i+n]*ifac[i]%p; } inline int binom(int n,int m){ if(n<m) return 0; return (ll)fac[n]*ifac[m]%p*ifac[n-m]%p; } int n,a,dp,dq; int f[N],P[N],Q[N],h[N]; const int inv2 = (p+1)/2; int main(){ read(n),read(a); init(n<<1); for(int i=0;i<=n;++i) read(f[i]); for(int i=n+1;i;--i) f[i] = (f[i]-(ll)a*f[i-1])%p; for(int i=n+2;i;--i) f[i] = (f[i]-2ll*a*f[i-1])%p; int pw = 1,c = power(p-2*a%p,p-2); n += 2; for(int i=0;i<=n;++i){ f[i] = ((ll)(f[i]+p)*pw)%p; pw = (ll)pw*c%p; } composite(f,n,p-1,f); for(int i=0;i<=n;++i){ if(i&1) Q[dq++] = f[i]; else P[dp++] = f[i]; } composite(P,dp-1,1,P),composite(Q,dq-1,1,Q); pw = 1,c = p-4ll*a%p; for(int i=0;(i<<1)<=n+1;++i){ P[i] = (ll)P[i]*pw%p,Q[i] = (ll)Q[i]*pw%p; pw = (ll)pw*c%p; } h[0] = pw = 1,c = 4ll*(p-a)%p; for(int i=1;i<=n;++i){ pw = (ll)pw*c%p*(inv2-i+1)%p; h[i] = (ll)pw*ifac[i]%p; } int lim = getlen(n<<1); dft(h,lim),dft(Q,lim); for(int i=0;i!=lim;++i) Q[i] = (ll)Q[i]*h[i]%p; idft(Q,lim); memset(Q+n+1,0,(lim-n)<<2); n -= 2; for(int i=0;i<=n;++i) f[i] = P[i]+Q[i]>=p?P[i]+Q[i]-p:P[i]+Q[i]; for(int i=1;i<=n;++i){ f[i] = (f[i]+4ll*a*f[i-1])%p; printf("%d ",f[i]); } return 0; }
- 1
信息
- ID
- 9436
- 时间
- 3000ms
- 内存
- 2048MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者