| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 人工智能 -> 【CF623E】Transforming Sequence(任意模数NTT) -> 正文阅读 |
|
[人工智能]【CF623E】Transforming Sequence(任意模数NTT) |
题面对于一个整数序列 { a 1 , a 2 , . . . , a n } \{a_1,a_2,...,a_n\} {a1?,a2?,...,an?},我们定义它的变换为 { b 1 , b 2 , . . . , b n } \{b_1,b_2,...,b_n\} {b1?,b2?,...,bn?},其中 b i = a 1 ∣ a 2 ∣ . . . ∣ a i b_i=a_1|a_2|...|a_i bi?=a1?∣a2?∣...∣ai?,其中 ∣ | ∣ 表示二进制按位或运算。 现在求有多少个长为 n n n 的序列 a a a,满足 1 ≤ a i ≤ 2 k ? 1 1\leq a_i\leq 2^k-1 1≤ai?≤2k?1,使得它的变换 b b b 是严格单调递增的,对 1 0 9 + 7 10^9+7 109+7 取模。 1 ≤ n ≤ 1 0 18 1\leq n\leq10^{18} 1≤n≤1018, 1 ≤ k ≤ 3 × 1 0 4 1\leq k\leq3\times10^4 1≤k≤3×104。 题解这题其实没有什么好说的,无非是几个步骤:推出式子 → 打出任意魔术NTT → 调试。我们一步一步来。 首先,这个变换其实是前缀按位或,前缀按位或如果要严格单调递增,那么每个数字都要至少存在一位 1 是前面的数字都没有的。所以 n > k n>k n>k 时一定无解,但这不重要。按照这个思路,容易发现,后一个数字的合法方案只取决于前面所有数字按位或后的二进制 1 个数。后一个数字的这些位——这些之前存在过 1 的位——都可以任意取 1 或 0,然后在这些位以外的地方再添加至少一个 1 位。这里我们先不考虑出现过 1 的位和没出现过 1 的位之间的相对位置,因为它可以最后考虑。 我们设
f
(
n
,
x
)
f(n,x)
f(n,x) 表示前
n
n
n 个数字,按位或起来存在
x
x
x 个 1 的方案数(忽视掉没出现过 1 的位)。那么考虑当前数字新添加的 1 的个数
x
?
i
x-i
x?i 、这
x
?
i
x-i
x?i 个 1 与之前的 1 的相对位置方案、以及之前的 1 位下可任意取 0 或 1 的方案,就可以得到下面的式子: 我们把组合数拆开,化成卷积形式: 我们发现,最终的多项式它完全没法化成
g
(
x
)
?
h
(
x
)
n
g(x)\cdot h(x)^n
g(x)?h(x)n 的形式,没法朴素地进行多项式幂。但是我们可以进行更灵活的倍增,把上式写成下面这个样子或许能启发思考: 我们可以试着不只转移一个数字,而是连续转移一段。我们插入一段数字,令这一段数字出现过 1 的所有位与前面的数字都不同,然后再在后面所有数字中,于前面出现 1 的位处任意取 0 和 1 ,可以最终得到一个无比类似的式子: 这样我们就可以做类快速幂了。 任意魔术NTT呢,一般是取 3 个不同的可以做NTT的模数分别做NTT,然后用中国剩余定理做回去。适用于每一次单独的多项式乘法,乘了过后要取模题目要求的模数,再继续下一步乘。 在用中国剩余定理的时候,由于数字极大,所以我们得用一个方法,在过程中取模题目要求的模数,并保证最终结果正确。 假设
N
T
T
NTT
NTT 用的三个模数分别为
M
1
,
M
2
,
M
3
M_1,M_2,M_3
M1?,M2?,M3? ,对于一个数字
x
x
x 有三个式子已知: 那么结果的表达式为 这三个逆元可以健康地求出来,然后……用 _ _ i n t 128 \rm\_\_int128 __int128 🙂🤮 开玩笑的,具体过程很繁杂,可以参见这位高职人员的详细解说:🔗 。 或者,你可以做真的猛士,去用 MTT 。 最后,调试的时候有必须注意的地方。如果你的NTT模数是 998244353 或者更小,那么对答案多项式进行一次正变换和逆变换后,与原来的多项式将不一定相同。原因就是,你用的是一个比 1 0 9 + 7 10^9+7 109+7 更小的模数。所以,每次进行 3 模NTT 时,要把转移多项式给存下来。 或者,你可以不用 469762049、998244353 和 1004535809 ,而是做个真的猛士,像我一样用上三个比 1 0 9 + 7 10^9+7 109+7 大的模数:
时间复杂度 O ( k log ? 2 k ) O(k\log^2k) O(klog2k) ,常数可观 ↓。 CODE我用的 _ _ i n t 128 \rm\_\_int128 __int128 ,危险行为请勿模仿。
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 22:31:48- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |