传送门


\(\begin{align*} Ans_k &= \sum\limits_{i=1}^n\sum\limits_{j=1}^m (a_i + b_j)^k \\ &= \sum\limits_{i=1}^n \sum\limits_{j=1}^m \sum\limits_{p=0}^k \binom{k}{p} a_i^p b_j^{k-p} \\ &= k! \sum\limits_{p=0}^k \frac{\sum\limits_{i=1}^n a_i^p}{p!}\frac{\sum\limits_{j=1}^m b_j^{k-p}}{(k-p)!} \end{align*}\)

最后的式子是一个卷积的形式,所以我们只需要求出多项式\(A(x) = \sum\limits_{p=0}^T \sum\limits_{i=1}^n a_i^p x^p\)和\(B(x) = \sum\limits_{p=0}^T \sum\limits_{i=1}^m b_i^p x^p\)的各项系数,就可以通过一次卷积求出答案。

显然的一件事情是\(A(x)\)和\(B(x)\)求法一样,所以我们只考虑\(A(x)\)

不难发现设\(F_i(x) = \sum\limits_{j=0}^\infty a_i^jx^j = \frac{1}{1-a_ix}\),那么\(A(x) = \sum\limits_{i=1}^n F_i(x)\)。直接暴力通分复杂度显然是\(O(n^2)\),但是不难发现和若干个二次多项式相乘一样,这个可以使用分治FFT优化通分,复杂度可以变为\(O(nlog^2n)\)。

但是因为分治FFT优化通分还是太慢所以及其容易被卡常,可以考虑当分治区间小到某个值以下时暴力通分。

多项式Ln的做法学不来qwq

  1. #include<bits/stdc++.h>
  2. //this code is written by Itst
  3. using namespace std;
  4. int read(){
  5. int a = 0; char c = getchar();
  6. while(!isdigit(c)) c = getchar();
  7. while(isdigit(c)){
  8. a = a * 10 + c - 48; c = getchar();
  9. }
  10. return a;
  11. }
  12. const int _ = (1 << 18) + 7 , MOD = 998244353;
  13. int poww(long long a , int b){
  14. int times = 1;
  15. while(b){
  16. if(b & 1) times = times * a % MOD;
  17. a = a * a % MOD; b >>= 1;
  18. }
  19. return times;
  20. }
  21. #define VI vector < int >
  22. namespace poly{
  23. const int G = 3 , INV = 332748118;
  24. int dir[_] , need , invnd;
  25. void init(int len){
  26. need = 1;
  27. while(need < len) need <<= 1;
  28. invnd = poww(need , MOD - 2);
  29. for(int i = 1 ; i < need ; ++i)
  30. dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0);
  31. }
  32. void NTT(VI &arr , int tp){
  33. arr.resize(need);
  34. for(int i = 1 ; i < need ; ++i)
  35. if(i < dir[i])
  36. arr[i] ^= arr[dir[i]] ^= arr[i] ^= arr[dir[i]];
  37. for(int i = 1 ; i < need ; i <<= 1){
  38. int wn = poww(tp == 1 ? G : INV , MOD / i / 2);
  39. for(int j = 0 ; j < need ; j += i << 1){
  40. long long w = 1;
  41. for(int k = 0 ; k < i ; ++k , w = w * wn % MOD){
  42. int x = arr[j + k] , y = arr[i + j + k] * w % MOD;
  43. arr[j + k] = x + y >= MOD ? x + y - MOD : x + y;
  44. arr[i + j + k] = x < y ? x + MOD - y : x - y;
  45. }
  46. }
  47. }
  48. if(tp != 1){
  49. for(int i = 0 ; i < need ; ++i)
  50. arr[i] = 1ll * arr[i] * invnd % MOD;
  51. int len = arr.size();
  52. while(len && arr[len - 1] == 0) --len;
  53. arr.resize(len);
  54. }
  55. }
  56. void mul(VI a , VI b , VI &c){
  57. int l = (int)(a.size() + b.size()) - 1;
  58. init(l); NTT(a , 1); NTT(b , 1); c.resize(need);
  59. for(int i = 0 ; i < need ; ++i)
  60. c[i] = 1ll * a[i] * b[i] % MOD;
  61. NTT(c , -1); c.resize(l);
  62. }
  63. void getInv(VI a , VI &b , int len){
  64. if(len == 1){b.resize(a.size()); return (void)(b[0] = poww(a[0] , MOD - 2));}
  65. getInv(a , b , (len + 1) >> 1);
  66. vector < int > A = a , B = b; A.resize(len); B.resize(len);
  67. init(A.size() + B.size() + 1); NTT(A , 1); NTT(B , 1);
  68. for(int i = 0 ; i < need ; ++i)
  69. A[i] = 1ll * A[i] * B[i] % MOD * B[i] % MOD;
  70. NTT(A , -1);
  71. for(int i = 0 ; i < len ; ++i)
  72. b[i] = (2ll * b[i] - A[i] + MOD) % MOD;
  73. }
  74. }
  75. using namespace poly;
  76. #define mid ((l + r) >> 1)
  77. #define lch (x << 1)
  78. #define rch (x << 1 | 1)
  79. vector < int > arr[_ << 2][2];
  80. int a[_] , b[_] , jc[_] , inv[_] , N , M , T;
  81. void solve(int x , int l , int r , int *num){
  82. arr[x][0].clear(); arr[x][1].clear();
  83. if(r - l <= 30){
  84. vector < int > &A = arr[x][0] , &B = arr[x][1] , tpa , tpb;
  85. init((r - l + 1) * 2); A.push_back(0); B.push_back(1);
  86. NTT(A , 1); NTT(B , 1);
  87. for(int i = l ; i <= r ; ++i){
  88. tpa.clear(); tpb.clear();
  89. tpa.push_back(1); tpb.push_back(1); tpb.push_back(MOD - num[i]);
  90. NTT(tpa , 1); NTT(tpb , 1);
  91. for(int i = 0 ; i < need ; ++i){
  92. A[i] = (1ll * A[i] * tpb[i] + 1ll * B[i] * tpa[i]) % MOD;
  93. B[i] = 1ll * B[i] * tpb[i] % MOD;
  94. }
  95. }
  96. NTT(A , -1); NTT(B , -1);
  97. }
  98. else{
  99. solve(lch , l , mid , num); solve(rch , mid + 1 , r , num);
  100. int l = arr[lch][1].size() + arr[rch][1].size();
  101. init(l); vector < int > a , b , c , d;
  102. arr[x][0].resize(need); arr[x][1].resize(need);
  103. a = arr[lch][0]; b = arr[lch][1]; c = arr[rch][0]; d = arr[rch][1];
  104. NTT(a , 1); NTT(b , 1); NTT(c , 1); NTT(d , 1);
  105. for(int i = 0 ; i < need ; ++i){
  106. arr[x][0][i] = (1ll * a[i] * d[i] + 1ll * b[i] * c[i]) % MOD;
  107. arr[x][1][i] = 1ll * b[i] * d[i] % MOD;
  108. }
  109. NTT(arr[x][0] , -1); NTT(arr[x][1] , -1);
  110. }
  111. }
  112. void init(){
  113. jc[0] = 1;
  114. for(int i = 1 ; i <= T ; ++i)
  115. jc[i] = 1ll * jc[i - 1] * i % MOD;
  116. inv[T] = poww(jc[T] , MOD - 2);
  117. for(int i = T - 1 ; i >= 0 ; --i)
  118. inv[i] = inv[i + 1] * (i + 1ll) % MOD;
  119. }
  120. int main(){
  121. #ifndef ONLINE_JUDGE
  122. freopen("in","r",stdin);
  123. //freopen("out","w",stdout);
  124. #endif
  125. N = read(); M = read();
  126. for(int i = 1 ; i <= N ; ++i) a[i] = read();
  127. for(int i = 1 ; i <= M ; ++i) b[i] = read();
  128. T = read(); init();
  129. vector < int > tp1 , tp2;
  130. solve(1 , 1 , N , a); arr[1][1].resize(T + 1); getInv(arr[1][1] , tp1 , T + 1);
  131. mul(tp1 , arr[1][0] , tp1); tp1.resize(T + 1);
  132. solve(1 , 1 , M , b); arr[1][1].resize(T + 1); getInv(arr[1][1] , tp2 , T + 1);
  133. mul(tp2 , arr[1][0] , tp2); tp2.resize(T + 1);
  134. for(int i = 0 ; i <= T ; ++i){
  135. tp1[i] = 1ll * tp1[i] * inv[i] % MOD;
  136. tp2[i] = 1ll * tp2[i] * inv[i] % MOD;
  137. }
  138. mul(tp1 , tp2 , tp1);
  139. int Inv = poww(1ll * N * M % MOD , MOD - 2);
  140. for(int i = 1 ; i <= T ; ++i)
  141. printf("%lld\n" , 1ll * tp1[i] * jc[i] % MOD * Inv % MOD);
  142. return 0;
  143. }

Luogu4705 玩游戏 分治FFT的更多相关文章

  1. luoguP4705 玩游戏 分治FFT

    \[ \begin{aligned} Ans(k) &= \sum \limits_{i = 1}^n \sum \limits_{j = 1}^m \sum \limits_{t = 0}^ ...

  2. [Luogu4705] 玩游戏

    Description 给定两个长度分别为 \(n\) 和 \(m\) 的序列 \(a\) 和 \(b\).要从这两个序列中分别随机一个数,设为 \(a_x,b_y\),定义该次游戏的 \(k\) 次 ...

  3. luogu4705玩游戏

    题解 我们要对于每个t,求一个(1/mn)sigma(ax+by)^t. 把系数不用管,把其他部分二项式展开一下: simga(ax^r*by^(t-r)*C(t,r)). 把组合数拆开,就变成了一个 ...

  4. 洛谷 P4705 玩游戏 解题报告

    P4705 玩游戏 题意:给长为\(n\)的\(\{a_i\}\)和长为\(m\)的\(\{b_i\}\),设 \[ f(x)=\sum_{k\ge 0}\sum_{i=1}^n\sum_{j=1}^ ...

  5. [题解] Luogu P4721 【模板】分治 FFT

    分治FFT的板子为什么要求逆呢 传送门 这个想法有点\(cdq\)啊,就是考虑分治,在算一段区间的时候,我们把他分成两个一样的区间,然后先做左区间的,算完过后把左区间和\(g\)卷积一下,这样就可以算 ...

  6. 原生JS实战:写了个一边玩游戏,一边记JS的API的游戏

    本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5878913.html 本程序[一边玩游戏,一边记JS的API]是本人的个 ...

  7. bzoj4730: Alice和Bob又在玩游戏

    Description Alice和Bob在玩游戏.有n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最 小的点.Alice和Bob轮流操作,每回合 ...

  8. BNUOJ 51279[组队活动 Large](cdq分治+FFT)

    传送门 大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案.两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中 ...

  9. 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和

    小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...

随机推荐

  1. 【loj3120】【CTS2019】珍珠

    题目 ​ $laofu $出的题 ​ \(n\)个离散型随机变量\(X_i\)可能的值为\([1,D]\) ,求有至少\(m\)对的概率 ​ $0 \le m \le 10^9  ,  1 \le n ...

  2. linux命令之------Chmod命令

    Chmod命令 1)作用:linux和unix的文件调用权限分为三级:文件拥有者/群组/其他.利用chmod可以控制文件如何被他人所调用.(主要就是修改文件夹,文件的权限) 2)U表示该文件的拥有者, ...

  3. 洛谷P1081 开车旅行

    题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...

  4. Java基础教程(全代码解析)

    字面量: 整数字面量为整型(int) 小数字面量为双精度浮点型(double) 数据类型: byte short int long float double 接下来代码展示理解 public clas ...

  5. GoCN每日新闻(2019-10-17)

    GoCN每日新闻(2019-10-17) 通过go module管理go tool https://marcofranssen.nl/manage-go-tools-via-go-modules/ 使 ...

  6. IDEA的foreach循环

    试了试其他快捷键, 突然发现的... 先弄一个list 再把变量名写出来先 按快捷键 ctrl+alt+J, 选最后一个 看效果

  7. beforeDestroy的使用

    beforeDestroy ---实例销毁之前调用 需求是这样的: important:下面截图数据都是测试数据 日期在我点击查询的时候要存储,刷新就读内存,但是我点击其他页面再进来的时候,这个内存要 ...

  8. JS filter的使用

    定义和用法 filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素. 注意: filter() 不会对空数组进行检测. 注意: filter() 不会改变原始数组 ...

  9. 【2019】Charles视频教程,接口测试工具最新教程

    Charles 是在 windows/mac/linux下常用的网络封包截取工具,也是电商/直播/搜索/金融/H5/App等测试专用接口测试工具. Charles 支持Http/Https/Webso ...

  10. opendaylight+sfc 发送测试流量报错找不到SFF Name

    问题介绍: 启动opendaylight sfc后,再启动sfc_agent.py,在SFC UI界面进行添加SF,SFF,SN:在部署SFC时,最后点击部署图标,sfc_agent.py报错如下: ...