由于$\mu(i)$,因此每一个素数最多存在1次,当$k=0$答案必然为0

根据莫比乌斯和欧拉函数的积性,答案与对素数的划分无关,仅与每一个素数是否出现有关,换言之枚举素数出现的集合$P'$,答案即为$\sum_{P'\subseteq P}(-1)^{|P'|}div(|P'|)\prod_{p\in P'}(p-1)$

(其中$div(n)$表示对$n$个数划分的方案数,当$k=1$时即$div(n)=1$)

令$f(x)=\sum_{i=0}^{\infty}(\sum_{|P'|=i}\prod_{p\in P'}(p-1))x^{i}$,答案即为$\sum_{i=0}^{\infty}(-1)^{i}div(i)f(x)[i]$

考虑求$f(x)$,当插入一个素数$p$,则$f(x)[i]=(p-1)f(x)[i-1]+f(x)[i]$,可以看作乘上$1+(p-1)x$这个多项式,重复此过程可得$f(x)=\prod_{p+1\in P}(1+px)$,分治fft即可

当$p=1$时$div(i)=1$,直接计算即可;当$p=2$时,考虑$div(i)$,即贝尔数,记作$B_{n}$

考虑其指数生成函数,即$f(x)=\sum_{i=0}^{\infty}\frac{B_{i}}{i!}x^{i}$

代入其递推式,即$f(x)=B_{0}+\sum_{i=1}^{\infty}\frac{\sum_{j=0}^{i-1}\frac{(i-1)!}{j!(i-j-1)!}B_{j}}{i!}x^{i}$

调换枚举顺序,即$f(x)=B_{0}+\sum_{j=0}^{\infty}\frac{B_{j}}{j!}\sum_{i=j+1}^{\infty}\frac{x^{i}}{i(i-j-1)!}$

对其求导,即$f'(x)=\sum_{j=0}^{\infty}\frac{B_{j}}{j!}\sum_{i=j}^{\infty}\frac{x^{i}}{(i-j)!}=\sum_{j=0}^{\infty}\frac{B_{j}x^{j}}{j!}\sum_{i=j}^{\infty}\frac{x^{i-j}}{(i-j)!}$

根据$e^{x}$泰勒展开的结果,后半部分即$e^{x}$,代入得$f'(x)=e^{x}\sum_{j=0}^{\infty}\frac{B_{j}x^{j}}{j!}=e^{x}f(x)$

考虑多项式$\frac{f'(x)}{f(x)}$,联系多项式ln的推导过程或对$\ln f(x)$求导,可得$\frac{f'(x)}{f(x)}=(\ln f(x))'=e^{x}$

对两边积分,即$\ln f(x)=e^{x}+C$,再同时exp,即$f(x)=e^{e^{x}+C}$,由于exp要求常数项为0,令$C=-1$即可,最终得到$f(x)=e^{e^{x}}-1$,多项式exp即可

由于素数个数为$\frac{n}{\ln n}$个,因此总复杂度为$o(n\log_{2}n)$,可以通过

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1000005
  4. 4 #define mod 998244353
  5. 5 struct poly{
  6. 6 vector<int>a;
  7. 7 }a,b;
  8. 8 int n,type,ans,p[N],vis[N];
  9. 9 int ksm(int n,int m){
  10. 10 if (!m)return 1;
  11. 11 int s=ksm(n,m>>1);
  12. 12 s=1LL*s*s%mod;
  13. 13 if (m&1)s=1LL*s*n%mod;
  14. 14 return s;
  15. 15 }
  16. 16 void ntt(poly &a,int n,int p){
  17. 17 for(int i=0;i<(1<<n);i++){
  18. 18 int rev=0;
  19. 19 for(int j=0;j<n;j++)rev=rev*2+((i&(1<<j))>0);
  20. 20 if (i<rev)swap(a.a[i],a.a[rev]);
  21. 21 }
  22. 22 for(int i=2;i<=(1<<n);i*=2){
  23. 23 int s=ksm(3,(mod-1)/i);
  24. 24 if (p)s=ksm(s,mod-2);
  25. 25 for(int j=0;j<(1<<n);j+=i)
  26. 26 for(int k=0,ss=1;k<(i>>1);k++,ss=1LL*ss*s%mod){
  27. 27 int x=a.a[j+k],y=1LL*ss*a.a[j+k+(i>>1)]%mod;
  28. 28 a.a[j+k]=(x+y)%mod;
  29. 29 a.a[j+k+(i>>1)]=(x+mod-y)%mod;
  30. 30 }
  31. 31 }
  32. 32 if (p){
  33. 33 int s=ksm((1<<n),mod-2);
  34. 34 for(int i=0;i<(1<<n);i++)a.a[i]=1LL*a.a[i]*s%mod;
  35. 35 }
  36. 36 }
  37. 37 poly dfs(int n,int l,int r){
  38. 38 poly ans;
  39. 39 if (n==1){
  40. 40 ans.a.push_back(1);
  41. 41 if ((!l)||(r>p[0]))ans.a.push_back(0);
  42. 42 else ans.a.push_back(p[l]-1);
  43. 43 ans.a.push_back(0);
  44. 44 ans.a.push_back(0);
  45. 45 return ans;
  46. 46 }
  47. 47 int mid=(l+r>>1);
  48. 48 poly L=dfs(n-1,l,mid),R=dfs(n-1,mid+1,r);
  49. 49 for(int i=0;i<(1<<n);i++)L.a.push_back(0);
  50. 50 for(int i=0;i<(1<<n);i++)R.a.push_back(0);
  51. 51 ntt(L,n+1,0);
  52. 52 ntt(R,n+1,0);
  53. 53 for(int i=0;i<(1<<n+1);i++)ans.a.push_back(1LL*L.a[i]*R.a[i]%mod);
  54. 54 ntt(ans,n+1,1);
  55. 55 return ans;
  56. 56 }
  57. 57 poly inv(int n,poly a){//返回为2^(n+1)次多项式
  58. 58 poly ans;
  59. 59 if (n==0){
  60. 60 ans.a.push_back(ksm(a.a[0],mod-2));
  61. 61 ans.a.push_back(0);
  62. 62 return ans;
  63. 63 }
  64. 64 ans=inv(n-1,a);
  65. 65 for(int i=0;i<(1<<n);i++)ans.a.push_back(0);
  66. 66 poly b=a;
  67. 67 for(int i=(1<<n);i<(1<<n+1);i++)b.a[i]=0;
  68. 68 ntt(ans,n+1,0);
  69. 69 ntt(b,n+1,0);
  70. 70 for(int i=0;i<(1<<n+1);i++)ans.a[i]=1LL*ans.a[i]*(mod+2-1LL*ans.a[i]*b.a[i]%mod)%mod;
  71. 71 ntt(ans,n+1,1);
  72. 72 for(int i=(1<<n);i<(1<<n+1);i++)ans.a[i]=0;
  73. 73 return ans;
  74. 74 }
  75. 75 poly ln(int n,poly a){//返回为2^(n+1)次多项式
  76. 76 poly ans=inv(n,a);
  77. 77 for(int i=0;i<(1<<n+1)-1;i++)a.a[i]=1LL*a.a[i+1]*(i+1)%mod;
  78. 78 a.a[(1<<n+1)-1]=0;
  79. 79 ntt(ans,n+1,0);
  80. 80 ntt(a,n+1,0);
  81. 81 for(int i=0;i<(1<<n+1);i++)ans.a[i]=1LL*ans.a[i]*a.a[i]%mod;
  82. 82 ntt(ans,n+1,1);
  83. 83 for(int i=(1<<n+1)-1;i;i--)ans.a[i]=1LL*ksm(i,mod-2)*ans.a[i-1]%mod;
  84. 84 ans.a[0]=0;
  85. 85 for(int i=(1<<n);i<(1<<n+1);i++)ans.a[i]=0;
  86. 86 return ans;
  87. 87 }
  88. 88 poly exp(int n,poly a){//返回为2^(n+1)次多项式
  89. 89 poly ans;
  90. 90 if (!n){
  91. 91 ans.a.push_back(1);
  92. 92 ans.a.push_back(0);
  93. 93 return ans;
  94. 94 }
  95. 95 ans=exp(n-1,a);
  96. 96 for(int i=0;i<(1<<n);i++)ans.a.push_back(0);
  97. 97 poly l=ln(n,ans);
  98. 98 for(int i=0;i<(1<<n);i++)l.a[i]=(a.a[i]-l.a[i]+mod)%mod;
  99. 99 for(int i=(1<<n);i<(1<<n+1);i++)l.a[i]=0;
  100. 100 l.a[0]++;
  101. 101 ntt(l,n+1,0);
  102. 102 ntt(ans,n+1,0);
  103. 103 for(int i=0;i<(1<<n+1);i++)ans.a[i]=1LL*ans.a[i]*l.a[i]%mod;
  104. 104 ntt(ans,n+1,1);
  105. 105 for(int i=(1<<n);i<(1<<n+1);i++)ans.a[i]=0;
  106. 106 return ans;
  107. 107 }
  108. 108 int main(){
  109. 109 scanf("%d%d",&n,&type);
  110. 110 if (!type){
  111. 111 printf("0");
  112. 112 return 0;
  113. 113 }
  114. 114 for(int i=2;i<=n;i++){
  115. 115 if (!vis[i]){
  116. 116 p[++p[0]]=i;
  117. 117 vis[i]=1;
  118. 118 }
  119. 119 for(int j=1;(j<=p[0])&&(i*p[j]<=n);j++){
  120. 120 vis[i*p[j]]=1;
  121. 121 if (i%p[j]==0)break;
  122. 122 }
  123. 123 }
  124. 124 a=dfs(18,0,(1<<17)-1);
  125. 125 if (type==1){
  126. 126 for(int i=1;i<=p[0];i++)
  127. 127 if (i&1)ans=(ans+mod-a.a[i])%mod;
  128. 128 else ans=(ans+a.a[i])%mod;
  129. 129 printf("%d",ans);
  130. 130 return 0;
  131. 131 }
  132. 132 b.a.push_back(0);
  133. 133 b.a.push_back(1);
  134. 134 for(int i=2;i<(1<<17);i++)b.a.push_back(1LL*b.a[i-1]*ksm(i,mod-2)%mod);
  135. 135 b=exp(17,b);
  136. 136 int fac=1;
  137. 137 for(int i=1;i<=p[0];i++){
  138. 138 fac=1LL*fac*i%mod;
  139. 139 int s=1LL*a.a[i]*b.a[i]%mod*fac%mod;
  140. 140 if (i&1)ans=(ans+mod-s)%mod;
  141. 141 else ans=(ans+s)%mod;
  142. 142 }
  143. 143 printf("%d",ans);
  144. 144 }

[luogu7092]计数题的更多相关文章

  1. ZOJ 3955 Saddle Point 校赛 一道计数题

    ZOJ3955 题意是这样的 给定一个n*m的整数矩阵 n和m均小于1000 对这个矩阵删去任意行和列后剩余一个矩阵为M{x1,x2,,,,xm;y1,y2,,,,,yn}表示删除任意的M行N列 对于 ...

  2. UOJ#428. 【集训队作业2018】普通的计数题

    #428. [集训队作业2018]普通的计数题 模型转化好题 所以变成统计有标号合法的树的个数. 合法限制: 1.根标号比子树都大 2.如果儿子全是叶子,数量B中有 3.如果存在一个儿子不是叶子,数量 ...

  3. D. Count the Arrays 计数题

    D. Count the Arrays 也是一个计数题. 题目大意: 要求构造一个满足题意的数列. \(n\) 代表数列的长度 数列元素的范围 \([1,m]\) 数列必须有且仅有一对相同的数 存在一 ...

  4. 【NOIP2017提高A组模拟9.7】JZOJ 计数题

    [NOIP2017提高A组模拟9.7]JZOJ 计数题 题目 Description Input Output Sample Input 5 2 2 3 4 5 Sample Output 8 6 D ...

  5. noip模拟44[我想我以后会碰见计数题就溜走的]

    noip模拟44 solutions 这一场抱零的也忒多了,我也只有45pts 据说好像是把几套题里面最难的收拾出来让我们考得 好惨烈啊,这次的考试我只有第一题骗了40pts,其他都抱零了 T1 Em ...

  6. FJOI2020 的两道组合计数题

    最近细品了 FJOI2020 的两道计数题,感觉抛开数据范围不清还卡常不谈里面的组合计数技巧还是挺不错的.由于这两道题都基于卡特兰数的拓展,所以我们把它们一并研究掉. 首先是 D1T3 ,先给出简要题 ...

  7. 「10.16晚」序列(....)·购物(性质)·计数题(DP)

    A. 序列 考场不认真读题会死..... 读清题就很简单了,分成若干块,然后块内递增,块外递减,同时使最大的块长为$A$ B. 购物 考场思路太局限了,没有发现性质, 考虑将$a_{i}$,排序前缀和 ...

  8. hdu-6415 Rikka with Nash Equilibrium dp计数题

    http://acm.hdu.edu.cn/showproblem.php?pid=6415 题意:将1~n*m填入一个n*m矩阵 问只有一个顶点的构造方案. 顶点的定义是:某数同时是本行本列的最大值 ...

  9. 【uoj428】普通的计数题

    Portal --> uoj428 Solution 不会胖子的一个log正解qwq只能怂怂滴写分治了qwq ​ 首先就是一个我想不到的转化qwq ​ 我们将第\(i\)次操作加入的数看成一个编 ...

随机推荐

  1. golang []byte和string的高性能转换

    golang []byte和string的高性能转换 在fasthttp的最佳实践中有这么一句话: Avoid conversion between []byte and string, since ...

  2. SpringBoot配置文件application

    配置文件 SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的,有两种文件格式: application.properties 语法结构 :key=value application. ...

  3. 阿里P8面试官:如何设计一个扛住千万级并发的架构?

    大家先思考一个问题,这也是在面试过程中经常遇到的问题. 如果你们公司现在的产品能够支持10W用户访问,你们老板突然和你说,融到钱了,会大量投放广告,预计在1个月后用户量会达到1000W,如果这个任务交 ...

  4. 2020.4.6--UCF Local Programming Contest 2017的正式赛

    Problem A : Electric Bill 题目大意:进行电量分级制收费,1000kwh及以下一档收费,1000kwh以上按另一档收费,给出每个人的电量总额,问每人应支付多少钱. 思路:基础i ...

  5. 是兄弟就来摸鱼 Scrum Meeting 博客汇总

    是兄弟就来摸鱼 Scrum Meeting 博客汇总 一.Alpha阶段 第一次Scrum meeting 第二次Scrum meeting 第三次Scrum meeting 第四次Scrum mee ...

  6. 搬运1:关于对C语言中数组名取地址加减等操作的一点探究

    对于数组名取地址强制转换的操作 偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西. 代码如下: #include<stdio.h> ...

  7. sort方法和自定义比较器的写法

    摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collections.sort()方法.对自定义对象排序 ...

  8. Flutter应用在夜神模拟器启动白屏问题

    Flutter应用在夜神模拟器启动白屏问题 flutter run  出现如下错误 [ERROR:flutter/shell/gpu/gpu_surface_gl.cc(39)] Failed to ...

  9. Go语言核心36讲(Go语言进阶技术十一)--学习笔记

    17 | go语句及其执行规则(下) 知识扩展 问题 1:怎样才能让主 goroutine 等待其他 goroutine? 我刚才说过,一旦主 goroutine 中的代码执行完毕,当前的 Go 程序 ...

  10. Python | 标识符命名规范

    简单地理解,标识符就是一个名字,就好像我们每个人都有属于自己的名字,它的主要作用就是作为变量.函数.类.模块以及其他对象的名称. Python 中标识符的命名不是随意的,而是要遵守一定的命令规则,比如 ...