题目描述

  问有多少个满足以下要求的\(k\)进制数:

   1.每个数字出现的次数不超过\(n\)

   2.\(0\)没有出现过

   3.若\(g_{i,j}=0\),则\(i\)不能出现恰好\(j\)次。

  两次询问之间会修改\(g\)中一个位置的值(\(0\)变\(1\)或\(1\)变\(0\))。

  输出所有询问的答案的和。

  \(3\leq k\leq 10,n\leq 14000,m\leq 20\)

  模数\(p=786433\),原根\(g=10\)

题解

  假设第\(i\)个数用了\(c_i\)个,答案为

\[\frac{(\sum c_i)!}{\prod c_i!}
\]

  构造多项式

\[f_i(x)=\sum_{j=0}^n\frac{g_{i,j}}{j!}x^j
\]

  把这\(k-1\)个多项式乘起来后,第\(i\)项乘以\(i!\)的和就是答案。

  因为求的是答案的和,所以可以在点值表达的形式下累加答案,最后IDFT回来。

​ 怎么求没修改前的答案?

  直接DFT

  怎么求修改的贡献?

  观察NTT的公式:

\[y_k=\sum_{j=0}^{n-1}a_j{(g^\frac{p-1}{n})}^{kj}
\]

  对于一个单点修改操作,可以看成在某个多项式上加上一个只有一项系数不为\(0\)的多项式。这个多项式DFT后就是一个等比数列,直接加到原多项式上就完了。

  对于所有多项式的乘积:如果所有多项式的每一项都非\(0\),就直接乘以逆元。现在有\(0\),就记录每一项\(0\)的个数和非\(0\)的乘积。

  时间复杂度:\(O(nk^2\log (nk)+mnk)\)

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<utility>
  7. using namespace std;
  8. typedef long long ll;
  9. typedef unsigned long long ull;
  10. typedef pair<int,int> pii;
  11. const ll p=786433;
  12. const ll g=10;
  13. ll inv[1000010];
  14. ll fac[1000010];
  15. ll ifac[1000010];
  16. ll pg[1000010];
  17. ll fp(ll a,ll b)
  18. {
  19. ll s=1;
  20. while(b)
  21. {
  22. if(b&1)
  23. s=s*a%p;
  24. a=a*a%p;
  25. b>>=1;
  26. }
  27. return s;
  28. }
  29. namespace ntt
  30. {
  31. int n;
  32. ll w1[150000];
  33. ll w2[150000];
  34. int rev[150000];
  35. void init(int x)
  36. {
  37. n=1;
  38. while(n<=x)
  39. n<<=1;
  40. int i;
  41. for(i=1;i<=n;i<<=1)
  42. {
  43. w1[i]=fp(g,(p-1)/i);
  44. w2[i]=inv[w1[i]];
  45. }
  46. rev[0]=0;
  47. for(i=1;i<n;i++)
  48. rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
  49. }
  50. void ntt(ll *a,int t)
  51. {
  52. int i,j,k;
  53. ll u,v,w,wn;
  54. for(i=0;i<=n-1;i++)
  55. if(rev[i]<i)
  56. swap(a[i],a[rev[i]]);
  57. for(i=2;i<=n;i<<=1)
  58. {
  59. wn=(t==1?w1[i]:w2[i]);
  60. for(j=0;j<n;j+=i)
  61. {
  62. w=1;
  63. for(k=j;k<j+i/2;k++)
  64. {
  65. u=a[k];
  66. v=a[k+i/2]*w%p;
  67. a[k]=(u+v)%p;
  68. a[k+i/2]=(u-v)%p;
  69. w=w*wn%p;
  70. }
  71. }
  72. }
  73. if(t==-1)
  74. for(i=0;i<n;i++)
  75. a[i]=a[i]*inv[n]%p;
  76. }
  77. }
  78. int &nn=ntt::n;
  79. char s[14010];
  80. int c[12][14010];
  81. void init()
  82. {
  83. int i;
  84. inv[0]=inv[1]=1;
  85. for(i=2;i<=p-1;i++)
  86. inv[i]=(-(p/i)*inv[p%i]%p+p)%p;
  87. fac[0]=ifac[0]=1;
  88. for(i=1;i<=p-1;i++)
  89. {
  90. fac[i]=fac[i-1]*i%p;
  91. ifac[i]=ifac[i-1]*inv[i]%p;
  92. }
  93. }
  94. ll ans;
  95. ll d[12][150000];
  96. ll f[150000];
  97. ll f2[150000];
  98. ll a[150000];
  99. int k,n,m;
  100. int main()
  101. {
  102. freopen("a.in","r",stdin);
  103. freopen("a.out","w",stdout);
  104. init();
  105. int i,j;
  106. scanf("%d%d%d",&k,&n,&m);
  107. ntt::init((k-1)*n);
  108. pg[0]=1;
  109. for(i=1;i<=p-2;i++)
  110. pg[i]=pg[i-1]*g%p;
  111. for(i=1;i<=k-1;i++)
  112. {
  113. scanf("%s",s);
  114. for(j=0;j<=n;j++)
  115. c[i][j]=s[j]-'0';
  116. }
  117. ans=0;
  118. for(i=0;i<nn;i++)
  119. f[i]=1;
  120. for(i=1;i<=k-1;i++)
  121. {
  122. ll *u=d[i];
  123. for(j=0;j<nn;j++)
  124. u[j]=0;
  125. for(j=0;j<=n;j++)
  126. u[j]=c[i][j]*ifac[j]%p;
  127. ntt::ntt(u,1);
  128. for(j=0;j<nn;j++)
  129. {
  130. if(u[j]<0)
  131. u[j]+=p;
  132. if(u[j])
  133. f[j]=f[j]*u[j]%p;
  134. else
  135. f2[j]++;
  136. }
  137. }
  138. for(i=0;i<nn;i++)
  139. if(!f2[i])
  140. a[i]=(a[i]+f[i])%p;
  141. int x,y;
  142. int t;
  143. for(t=1;t<=m;t++)
  144. {
  145. scanf("%d%d",&x,&y);
  146. c[x][y]^=1;
  147. for(i=0;i<nn;i++)
  148. if(d[x][i])
  149. f[i]=f[i]*inv[d[x][i]]%p;
  150. else
  151. f2[i]--;
  152. ll s1=pg[((p-1)/nn*y)%(p-1)],s2=ifac[y];
  153. if(!c[x][y])
  154. s2=p-s2;
  155. for(i=0;i<nn;i++)
  156. {
  157. d[x][i]+=s2;
  158. if(d[x][i]>=p)
  159. d[x][i]-=p;
  160. s2=s2*s1%p;
  161. }
  162. for(i=0;i<nn;i++)
  163. {
  164. if(d[x][i])
  165. f[i]=f[i]*d[x][i]%p;
  166. else
  167. f2[i]++;
  168. if(!f2[i])
  169. a[i]=(a[i]+f[i])%p;
  170. }
  171. }
  172. ntt::ntt(a,-1);
  173. for(i=1;i<nn;i++)
  174. ans=(ans+a[i]*fac[i])%p;
  175. ans=(ans%p+p)%p;
  176. printf("%lld\n",ans);
  177. return 0;
  178. }

【XSY2535】整数 NTT的更多相关文章

  1. [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)

    目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...

  2. Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)

    题目 Source http://www.tsinsen.com/A1493 Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在 ...

  3. NTT

    1 问题描述FFT问题解决的是复数域上的卷积.如果现在的问题是这样:给出两个整数数列$Ai,Bj,0\leq i\leq n-1,0\leq j\leq m-1$,以及素数$P$,计算新数列$Ci=( ...

  4. 卷积FFT、NTT、FWT

    先简短几句话说说FFT.... 多项式可用系数和点值表示,n个点可确定一个次数小于n的多项式. 多项式乘积为 f(x)*g(x),显然若已知f(x), g(x)的点值,O(n)可求得多项式乘积的点值. ...

  5. FFT\NTT总结

    学了好久,终于基本弄明白了 推荐两个博客: 戳我 戳我 再推荐几本书: <ACM/ICPC算法基础训练教程> <组合数学>(清华大学出版社) <高中数学选修> 预备 ...

  6. 快速傅里叶变换FFT& 数论变换NTT

    相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...

  7. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

  8. 【2019雅礼集训】【CF 960G】【第一类斯特林数】【NTT&多项式】permutation

    目录 题意 输入格式 输出格式 思路 代码 题意 找有多少个长度为n的排列,使得从左往右数,有a个元素比之前的所有数字都大,从右往左数,有b个元素比之后的所有数字都大. n<=2*10^5,a, ...

  9. 快速数论变换(NTT)小结

    NTT 在FFT中,我们需要用到复数,复数虽然很神奇,但是它也有自己的局限性--需要用double类型计算,精度太低 那有没有什么东西能够代替复数且解决精度问题呢? 这个东西,叫原根 原根 阶 若\( ...

随机推荐

  1. vue prop 传递数据

    prop 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据.要让子组件使用父组件的数据,需要通过子组件的 props 选项 一个组件默认可以拥有任意数量的 p ...

  2. docker的4种网络模型

    我们在使用docker run创建Docker容器时,可以用--net选项指定容器的网络模式,Docker有以下4种网络模式: · host模式,使用--net=host指定. · container ...

  3. 牛客国庆集训派对Day2

    题目链接:https://www.nowcoder.com/acm/contest/202/A A 题意:给出最大4096*64和64*4096的矩阵,其中有一个矩阵只含有0和1,问你它们相乘所得到得 ...

  4. Mysql 索引问题集锦

    一.Mysql 中的索引 索引:顾名思义用来检索.查找数据的key (字段) 几种Mysql 中的常见索引分类:普通索引(联合索引).唯一索引.主键索引.全文索引 优点:使得查询数据变快 缺点:更新数 ...

  5. Windows之PowerShell使用命令

    Windows之PowerShell使用命令 切换 命令格式: cd [option] 切换到上一级目录 cd ../ 或者 cd .. 不同磁盘之间切换 盘符: 清屏 清空当前窗口的内容 cls 查 ...

  6. ES5与ES6的小差异

    ES5与ES6的小差异 变量的定义 ES6与ES5的区别 ES5: <script> console.log(username); var username; var username = ...

  7. Python_生成随机百分比的方法

    可以使用random模块去实现,给定1到100的空间,使用random的choice的方法随机选取一个数字,当这个数字在某个区间时就可以认定为出发了指定的百分比的概率. 这个简单的逻辑也可以在需要时扩 ...

  8. [转帖]IP /TCP协议及握手过程和数据包格式中级详解

    IP /TCP协议及握手过程和数据包格式中级详解 https://www.toutiao.com/a6665292902458982926/ 写的挺好的 其实 一直没闹明白 网络好 广播地址 还有 网 ...

  9. Redis 使用命令行的方式 获取 hash type key 的value值

    1. 之前只是非常简单的看了下 get key 和 set key 但是这样 设置的 key value 应该是都 string 类型的 2. 但是没考虑过其他类型的 是如何获取 相关内容的 ,一直 ...

  10. oracle计算时间常用函数

    --ddd:一年中的第几天 select to_char(sysdate,'ddd') from dual --d:一周中的第几天 星期天是第一天 所以要-1select to_char(sysdat ...