[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\) 项的新二进制位个数, 那么转移显然:
\]
统计答案的时候枚举总共出现的二进制位个数:
\]
状态数是 \(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\) 位呢?
这次应该是这样的转移式:
\]
我们相当于在一个长度为 \(i-m\) 的序列后面接了长度为 \(m\) 的序列并用组合数让他们的二进制位互不干扰. 但是后面接的长度为 \(m\) 的数列里面是完全不包含前面 \(i-m\) 中的二进制位的方案的. 这些位由于在前面已经出现过, 所以在后面长度为 \(m\) 的数列里是任选的. 一共有 \(m(j-k)\) 位.
下标相同的并在一起就又是个二项卷积了, 倍增就好了. 复杂度 \(O(k \log k \log n)\).
参考代码
#include <bits/stdc++.h>
const int G=3;
const int DFT=1;
const int IDFT=-1;
const int MAXN=1e5+10;
const int MOD=998244353;
const int PHI=MOD-1;
int n;
int k;
int dp[MAXN];
int pw[MAXN];
int tr[MAXN];
int tx[MAXN];
int rev[MAXN];
int fact[MAXN];
int C(int,int);
int Pow(int,int,int);
void NTT(int*,int,int);
int main(){
scanf("%d%d",&n,&k);
pw[0]=1;
fact[0]=1;
for(int i=1;i<=k;i++){
pw[i]=(pw[i-1]<<1)%MOD;
fact[i]=1ll*fact[i-1]*i%MOD;
tr[i]=Pow(fact[i],MOD-2,MOD);
}
int bln=1,bct=0;
while(bln<=k*2){
bln<<=1;
++bct;
}
for(int i=0;i<bln;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
NTT(tr,bln,DFT);
dp[0]=1;
int cur=1;
while(n>0){
if(n&1){
for(int i=k+1;i<bln;i++)
dp[i]=0;
for(int i=0;i<=k;i++)
dp[i]=1ll*dp[i]*Pow(pw[i],cur,MOD)%MOD;
NTT(dp,bln,DFT);
for(int i=0;i<bln;i++)
dp[i]=1ll*dp[i]*tr[i]%MOD;
NTT(dp,bln,IDFT);
}
NTT(tr,bln,IDFT);
for(int i=k+1;i<bln;i++)
tx[i]=0;
for(int i=0;i<=k;i++)
tx[i]=1ll*tr[i]*Pow(pw[i],cur,MOD)%MOD;
NTT(tx,bln,DFT);
NTT(tr,bln,DFT);
for(int i=0;i<bln;i++)
tr[i]=1ll*tr[i]*tx[i]%MOD;
NTT(tr,bln,IDFT);
for(int i=k+1;i<bln;i++)
tr[i]=0;
NTT(tr,bln,DFT);
n>>=1;
cur<<=1;
}
int ans=0;
for(int i=0;i<=k;i++)
(ans+=1ll*dp[i]*fact[i]%MOD*C(k,i)%MOD)%=MOD;
printf("%d\n",ans);
return 0;
}
int C(int n,int m){
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;
}
void NTT(int* a,int len,int opt){
for(int i=0;i<len;i++)
if(rev[i]>i)
std::swap(a[i],a[rev[i]]);
for(int i=1;i<len;i<<=1){
int step=i<<1;
int wn=Pow(G,(opt*PHI/step+PHI)%PHI,MOD);
for(int j=0;j<len;j+=step){
int w=1;
for(int k=0;k<i;k++,w=1ll*w*wn%MOD){
int x=a[j+k];
int y=1ll*a[j+k+i]*w%MOD;
a[j+k]=(x+y)%MOD;
a[j+k+i]=(x-y+MOD)%MOD;
}
}
}
if(opt==IDFT){
int inv=Pow(len,MOD-2,MOD);
for(int i=0;i<len;i++)
a[i]=1ll*a[i]*inv%MOD;
}
}
inline int Pow(int a,int n,int p){
int ans=1;
while(n>0){
if(n&1)
ans=1ll*a*ans%p;
a=1ll*a*a%p;
n>>=1;
}
return ans;
}
[2018HN省队集训D1T3] Or的更多相关文章
-
[2018HN省队集训D9T1] circle
[2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...
-
[2018HN省队集训D8T1] 杀毒软件
[2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...
-
[2018HN省队集训D8T3] 水果拼盘
[2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...
-
[2018HN省队集训D6T2] girls
[2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...
-
[Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform
[Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...
-
[2018HN省队集训D5T2] party
[2018HN省队集训D5T2] party 题意 给定一棵 \(n\) 个点以 \(1\) 为根的有根树, 每个点有一个 \([1,m]\) 的权值. 有 \(q\) 个查询, 每次给定一个大小为 ...
-
[2018HN省队集训D5T1] 沼泽地marshland
[2018HN省队集训D5T1] 沼泽地marshland 题意 给定一张 \(n\times n\) 的棋盘, 对于位置 \((x,y)\), 若 \(x+y\) 为奇数则可能有一个正权值. 你可以 ...
-
[Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard
[Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard 题意 给定一个 \(n\times n\) 的矩阵 \(A\), (\(n\) 为奇数) , ...
-
[2018HN省队集训D1T1] Tree
[2018HN省队集训D1T1] Tree 题意 给定一棵带点权树, 要求支持下面三种操作: 1 root 将 root 设为根. 2 u v d 将以 \(\operatorname{LCA} (u ...
随机推荐
-
HBase+Phoenix整合入门--集群搭建
环境:CentOS 6.6 64位 hbase 1.1.15 phoenix-4.7.0-HBase-1.1 一.前置环境: 已经安装配置好Hadoop 2.6和jdk 1.7 二.安装hba ...
-
Excel VBA 函数
Instr函数 一. 定义 InStr 函数 返回 Variant (Long),指定一字符串在另一字符串中最先出现的位置. InStr([start, ]string1, string2[, com ...
-
DWR实现后台推送消息到web页面
DWR简介 DWR(Direct Web Remoting)可用于实现javascript直接调用java函数和后台直接调用页面javascript代码,后者可用作服务端推送消息到Web前端. (服务 ...
-
[手机取证] “神器”IP-BOX的一些问题
网上最近传的纷纷扬扬的iOS密码破解神器IP-BOX,很多人感兴趣,作为一个该产品的老用户,来破除一下迷信,顺便做个普及~ Q1:这东西好神奇,是不是所有都能破解? A1:支持简单密码的穷举,有条件的 ...
-
【leetcode】Climbing Stairs (easy)
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...
-
$设置背景图片的css
$('.d-game-pic').css('background-image', 'url(' + App.getImg(gameDetail.desc_pic) + ')');
-
【原创】java 流星划过天空
import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.s ...
-
phpQuery轻松采集网页内容
原文地址:phpQuery轻松采集网页内容作者:陌上花开 phpQuery是一个基于PHP的服务端开源项目,它可以让PHP开发人员轻松处理DOM文档内容,比如获取某新闻网站的头条信息.更有意思的是,它 ...
-
Android 监控网络状态
public static boolean isNetworkAvailable(Context context) { ConnectivityManager connectivity = (Conn ...
-
数据结构学习java(一点五)链式顺序表(链表)
java中没有将指针暴露给用户(以前做过看过一篇文章写有java中是有指针的,只是被藏起来了),所以得使用引用的方式. 何为引用请看下面这篇文章(写的很不错,当然肯定比我写的好): https://w ...