[关闭]
@ysner 2018-09-19T17:07:39.000000Z 字数 2236 阅读 1605

[HEOI2016/TJOI2016]求和

FFT/NTT 数论


题面

解析

觉得这道题目与[bzoj5093]图的价值相比,还是小巫见大巫呢。
公式复杂程度和代码细节量少了不止一个级别。。。

首先,要求的时间复杂度是
则我们需要卷积形式的,第二类斯特林数的,通项公式:(推导过程在链接的那篇博文里)


然后推推式子:

注意到时,,我们可以扩大的范围:

所以题目实际上要求我们把化成卷积形式。



又根据等比数列求和公式

最终式子化为

大功告成。接下来轻松解决。

ps:如何快速求阶乘的逆元

显然一般方法是一边求阶乘一边求逆元,复杂度
然而更好的方法是求完阶乘后,求出最后一个阶乘的逆元,再不断即可。
时间复杂度

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=4e5+1,mod=998244353;
  14. int n,m,lim=1,l,r[N],a[N],b[N],jc[N],inv[N],ans;
  15. il int ksm(re int S,re int n)
  16. {
  17. re int T=S;S=1;
  18. while(n)
  19. {
  20. if(n&1) S=1ll*S*T%mod;
  21. T=1ll*T*T%mod;
  22. n>>=1;
  23. }
  24. return S;
  25. }
  26. il void NTT(re int *A,re int tp)
  27. {
  28. fp(i,1,lim-1) if(i<r[i]) swap(A[i],A[r[i]]);
  29. for(re int mid=1;mid<lim;mid<<=1)
  30. {
  31. re int gu=mid<<1,W=ksm(3,(mod-1)/gu);
  32. if(tp==-1) W=ksm(W,mod-2);
  33. for(re int j=0;j<lim;j+=gu)
  34. {
  35. re int w=1;
  36. for(re int k=0;k<mid;k++,w=1ll*w*W%mod)
  37. {
  38. re ll x=A[j+k],y=1ll*w*A[j+mid+k]%mod;
  39. A[j+k]=(x+y)%mod;A[j+mid+k]=(x-y+mod)%mod;
  40. }
  41. }
  42. }
  43. }
  44. il int gi()
  45. {
  46. re int x=0,t=1;
  47. re char ch=getchar();
  48. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  49. if(ch=='-') t=-1,ch=getchar();
  50. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  51. return x*t;
  52. }
  53. int main()
  54. {
  55. n=m=gi();
  56. jc[0]=inv[0]=1;fp(i,1,n) jc[i]=1ll*jc[i-1]*i%mod;
  57. inv[n]=ksm(jc[n],mod-2);
  58. fq(i,n-1,1) inv[i]=1ll*inv[i+1]*(i+1)%mod;
  59. b[0]=1;b[1]=n+1;
  60. fp(i,0,n)
  61. {
  62. a[i]=(i&1)?mod-inv[i]:inv[i];
  63. if(i>1) b[i]=1ll*(ksm(i,n+1)-1+mod)%mod*ksm(i-1,mod-2)%mod*inv[i]%mod;
  64. }
  65. while(lim<=n+m) lim<<=1,++l;
  66. fp(i,1,lim-1) r[i]=(r[i>>1]>>1)|((i&1)<<l-1);
  67. NTT(a,1);NTT(b,1);
  68. fp(i,0,lim-1) a[i]=1ll*a[i]*b[i]%mod;
  69. NTT(a,-1);
  70. re ll Inv=ksm(lim,mod-2);
  71. for(re int i=0,j=1;i<=n;++i,j=((ll)j<<1)%mod)
  72. (ans+=1ll*a[i]*Inv%mod*jc[i]%mod*j%mod)%=mod;
  73. printf("%d\n",ans);
  74. return 0;
  75. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注