[2018HN省队集训D1T3] Or

题意

给定 \(n\) 和 \(k\), 求长度为 \(n\) 的满足下列条件的数列的数量模 \(998244353\) 的值:

  • 所有值在 \([1,2^k)\) 中
  • 前缀或的值严格递增

\(n,k\le 3\times 10^4\)

题解

这题有点意思

首先肯定每一项都得有新出现的二进制位, 于是可以想到一个超简单的 \(O(nk^2)\) 的DP, 设 \(dp_{i,j}\) 为长度为 \(i\) 且已经出现了 \(j\) 个二进制位的数列的个数. 然后考虑枚举数列第 \(i\) 项的新二进制位个数, 那么转移显然:

\[dp_{i,j}=\sum_{k=1}^j {j\choose k} dp_{i-1,j-k}2^{j-k}
\]

统计答案的时候枚举总共出现的二进制位个数:

\[\text{Ans}=\sum_{i=1}^k{k\choose i}dp_{n,i}
\]

状态数是 \(O(nk)\) 的, 朴素转移 \(O(k)\), 总复杂度 \(O(nk^2)\).

机智的我们一眼看出后面的转移式子就是个二项卷积, 随手比个阶乘打个NTT上去就变成 \(O(nk\log k)\) 了.

然而这还不够.

我们发现一次转移相当于一次卷积和一次点积, 我们肯定想这玩意能不能快速幂一发.

然后我们非常sad地发现由于里面那个 \(2^{j-k}\) 搞事情所以不能裸快速幂.

考虑这个 \(2^{j-k}\) 是拿来干啥的. \(k\) 是第 \(i\) 项的新二进制位个数, \(j\) 是前 \(i\) 项已经出现过的二进制位个数, \(j-k\) 是前 \(i-1\) 项已经出现的二进制位个数. 显然这些前 \(i-1\) 项中出现过的二进制位在第 \(i\) 项中是任选的, 于是我们需要乘上这玩意.

那么如果转移不是 \(1\) 位而是 \(m\) 位呢?

这次应该是这样的转移式:

\[dp_{i,j}=\sum_{k=1}^j{j\choose k} dp_{i-m,j-k}dp_{m,k}2^{(j-k)m}
\]

我们相当于在一个长度为 \(i-m\) 的序列后面接了长度为 \(m\) 的序列并用组合数让他们的二进制位互不干扰. 但是后面接的长度为 \(m\) 的数列里面是完全不包含前面 \(i-m\) 中的二进制位的方案的. 这些位由于在前面已经出现过, 所以在后面长度为 \(m\) 的数列里是任选的. 一共有 \(m(j-k)\) 位.

下标相同的并在一起就又是个二项卷积了, 倍增就好了. 复杂度 \(O(k \log k \log n)\).

参考代码

  1. #include <bits/stdc++.h>
  2. const int G=3;
  3. const int DFT=1;
  4. const int IDFT=-1;
  5. const int MAXN=1e5+10;
  6. const int MOD=998244353;
  7. const int PHI=MOD-1;
  8. int n;
  9. int k;
  10. int dp[MAXN];
  11. int pw[MAXN];
  12. int tr[MAXN];
  13. int tx[MAXN];
  14. int rev[MAXN];
  15. int fact[MAXN];
  16. int C(int,int);
  17. int Pow(int,int,int);
  18. void NTT(int*,int,int);
  19. int main(){
  20. scanf("%d%d",&n,&k);
  21. pw[0]=1;
  22. fact[0]=1;
  23. for(int i=1;i<=k;i++){
  24. pw[i]=(pw[i-1]<<1)%MOD;
  25. fact[i]=1ll*fact[i-1]*i%MOD;
  26. tr[i]=Pow(fact[i],MOD-2,MOD);
  27. }
  28. int bln=1,bct=0;
  29. while(bln<=k*2){
  30. bln<<=1;
  31. ++bct;
  32. }
  33. for(int i=0;i<bln;i++)
  34. rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
  35. NTT(tr,bln,DFT);
  36. dp[0]=1;
  37. int cur=1;
  38. while(n>0){
  39. if(n&1){
  40. for(int i=k+1;i<bln;i++)
  41. dp[i]=0;
  42. for(int i=0;i<=k;i++)
  43. dp[i]=1ll*dp[i]*Pow(pw[i],cur,MOD)%MOD;
  44. NTT(dp,bln,DFT);
  45. for(int i=0;i<bln;i++)
  46. dp[i]=1ll*dp[i]*tr[i]%MOD;
  47. NTT(dp,bln,IDFT);
  48. }
  49. NTT(tr,bln,IDFT);
  50. for(int i=k+1;i<bln;i++)
  51. tx[i]=0;
  52. for(int i=0;i<=k;i++)
  53. tx[i]=1ll*tr[i]*Pow(pw[i],cur,MOD)%MOD;
  54. NTT(tx,bln,DFT);
  55. NTT(tr,bln,DFT);
  56. for(int i=0;i<bln;i++)
  57. tr[i]=1ll*tr[i]*tx[i]%MOD;
  58. NTT(tr,bln,IDFT);
  59. for(int i=k+1;i<bln;i++)
  60. tr[i]=0;
  61. NTT(tr,bln,DFT);
  62. n>>=1;
  63. cur<<=1;
  64. }
  65. int ans=0;
  66. for(int i=0;i<=k;i++)
  67. (ans+=1ll*dp[i]*fact[i]%MOD*C(k,i)%MOD)%=MOD;
  68. printf("%d\n",ans);
  69. return 0;
  70. }
  71. int C(int n,int m){
  72. return n<0||m<0||n<m?0:1ll*fact[n]*Pow(fact[m],MOD-2,MOD)%MOD*Pow(fact[n-m],MOD-2,MOD)%MOD;
  73. }
  74. void NTT(int* a,int len,int opt){
  75. for(int i=0;i<len;i++)
  76. if(rev[i]>i)
  77. std::swap(a[i],a[rev[i]]);
  78. for(int i=1;i<len;i<<=1){
  79. int step=i<<1;
  80. int wn=Pow(G,(opt*PHI/step+PHI)%PHI,MOD);
  81. for(int j=0;j<len;j+=step){
  82. int w=1;
  83. for(int k=0;k<i;k++,w=1ll*w*wn%MOD){
  84. int x=a[j+k];
  85. int y=1ll*a[j+k+i]*w%MOD;
  86. a[j+k]=(x+y)%MOD;
  87. a[j+k+i]=(x-y+MOD)%MOD;
  88. }
  89. }
  90. }
  91. if(opt==IDFT){
  92. int inv=Pow(len,MOD-2,MOD);
  93. for(int i=0;i<len;i++)
  94. a[i]=1ll*a[i]*inv%MOD;
  95. }
  96. }
  97. inline int Pow(int a,int n,int p){
  98. int ans=1;
  99. while(n>0){
  100. if(n&1)
  101. ans=1ll*a*ans%p;
  102. a=1ll*a*a%p;
  103. n>>=1;
  104. }
  105. return ans;
  106. }

[2018HN省队集训D1T3] Or的更多相关文章

  1. [2018HN省队集训D9T1] circle

    [2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...

  2. [2018HN省队集训D8T1] 杀毒软件

    [2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...

  3. [2018HN省队集训D8T3] 水果拼盘

    [2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...

  4. [2018HN省队集训D6T2] girls

    [2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...

  5. [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform

    [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...

  6. [2018HN省队集训D5T2] party

    [2018HN省队集训D5T2] party 题意 给定一棵 \(n\) 个点以 \(1\) 为根的有根树, 每个点有一个 \([1,m]\) 的权值. 有 \(q\) 个查询, 每次给定一个大小为 ...

  7. [2018HN省队集训D5T1] 沼泽地marshland

    [2018HN省队集训D5T1] 沼泽地marshland 题意 给定一张 \(n\times n\) 的棋盘, 对于位置 \((x,y)\), 若 \(x+y\) 为奇数则可能有一个正权值. 你可以 ...

  8. [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard

    [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard 题意 给定一个 \(n\times n\) 的矩阵 \(A\), (\(n\) 为奇数) , ...

  9. [2018HN省队集训D1T1] Tree

    [2018HN省队集训D1T1] Tree 题意 给定一棵带点权树, 要求支持下面三种操作: 1 root 将 root 设为根. 2 u v d 将以 \(\operatorname{LCA} (u ...

随机推荐

  1. 手机浏览器_安卓_苹果手机Webview 中唤醒APP

    Url scheme是iOS,Android平台都支持,只需要原生APP开发时注册scheme, 那么用户点击到此类链接时,会自动跳到APP.比如 <!-- 打开考拉APP首页 --> & ...

  2. BOM-使用定时器

    window对象包含4个定时器专用方法,说明如下表所示,使用它们可以实现代码定时运行,避免连续执行,这样可以设计动画 方法 说明 setInterval() 按照指定的周期,(以毫秒为单位)来调用函数 ...

  3. [android] 手机卫士接收打电话广播显示号码归属地

    使用广播接收者接收打电话的意图,显示号码归属地 新建一个类OutCallReceiver继承系统的BroadcastReceiver 重写onReceive()方法 调用getResultData() ...

  4. SEDA架构程序实现

    一.SEDA SEDA全称是:stage event driver architecture,中文直译为“分阶段的事件驱动架构”,它旨在结合事件驱动和多线程模式两者的优点,从而做到易扩展,解耦合,高并 ...

  5. gRPC的通讯过程

    在 HTTP2 协议正式开始工作前, 如果已经知道服务器是 HTTP2 的服务器, 通讯流程如下: 客户端必须首先发送一个连接序言,其逻辑结构: PRI * HTTP/2.0\r\n\r\nSM\r\ ...

  6. SpingMVC_注解式开发_接收请求参数

    一.逐个接收 import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotat ...

  7. Android开发之旅4:应用程序基础及组件

    引言 为了后面的例子做准备,本篇及接下来几篇将介绍Android应用程序的原理及术语,这些也是作为一个Android的开发人员必须要了解,且深刻理解的东西.本篇的主题如下: 1.应用程序基础 2.应用 ...

  8. Python Django 获取表单数据的三种方式

    # In viewsdef zbsservice(request): #返回一个列表 v1 = models.Business.objects.all() # .value返回一个字典 v2 = mo ...

  9. Element ui 中使用table组件实现分页记忆选中

    我们再用vue和element-ui,或者其他的表格的时候,可能需要能记忆翻页勾选,那么实现以下几个方法就ok了 示例如下 <el-table :data="tableData&quo ...

  10. PHP通用分页类page.php[仿google分页]

    <?php /** ** 通用php分页类.(仿Google样式) ** 只需提供记录总数与每页显示数两个参数.(已附详细使用说明..) ** 无需指定URL,链接由程序生成.方便用于检索结果分 ...