线性求 \(i^i\) 的做法

方便起见,我们记 \(f_i=i^i\),\(i\) 的最小质因子为 \(p=\mathrm{minp}(i)\),第 \(i\) 个质数为 \(\mathrm{pr}_i\)。

对于质数 \(p\) 用快速幂计算,这里复杂度 \(\mathcal O(\frac{n}{\ln n}\log n)\)。

对于合数 \(i=pq\),\(f_i=(pq)^{pq}=f_p^qf_q^p\),由于 \(p\le \sqrt{n}\),因此我们可以 BSGS 预处理 \(f_p^{1\cdots B}\) 以及 \((f_p^B)^{1\cdots B}\)。

考虑如何快速计算后半部分。回顾线性筛的流程,\(i\) 是在外层枚举到 \(q\),内层枚举到 \(p\) 时计算,因此对于 \(q\) 而言,它计算的东西依次为 \(f_q^{\mathrm{pr}_1,\mathrm{pr}_2,\cdots}\),指数增量是 prime gap,即 \(\mathcal O(\ln n)\),因此可以预处理出 \(f_q^{1,2,\cdots,\ln \frac{n}{q}}\),这里复杂度 \(\mathcal O(\frac{n/q}{\ln (n/q)}+\ln \frac{n}{q})\),累加起来 \(\mathcal O(n)\)(实测中,由于枚举到 \(p=\mathrm{minp}(q)\) 就会 break,所以常数极小)。

上面这个 \(1,2,\cdots,\ln \frac{n}{q}\) 也可以用 BSGS 优化到 \(\sqrt{\ln \frac{n}{q}}\),不过没啥影响,说不定还跑不过直接暴力。​

时间复杂度 \(\mathcal O(n)\)。


下面是一些实验性代码:

\(\mathcal O(n)\) 的实现

const int N = 100000005;
const int SN = ((int)sqrt(N) + 5);
const int mod = 998244353; int qpow(int a, int b) {
int res = 1;
while (b > 0) {
if (b & 1) res = 1ull * res * a % mod;
a = 1ull * a * a % mod, b >>= 1;
}
return res;
} int bsgs1[SN][SN], bsgs2[SN][SN];
bool vis[N];
int f[N], pr[N / 10], len;
int powers[250], S; void sieve(int n) {
f[1] = 1;
const int B = sqrt(n);
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
pr[++len] = i;
f[i] = qpow(i, i);
if (i <= B) {
bsgs1[i][0] = 1;
for (int j = 1; j <= B; j++)
bsgs1[i][j] = 1ull * bsgs1[i][j - 1] * f[i] % mod;
bsgs2[i][0] = 1;
for (int j = 1; j <= B; j++)
bsgs2[i][j] = 1ull * bsgs2[i][j - 1] * bsgs1[i][B] % mod;
}
}
powers[0] = 1;
int cur = 1, gap = 0;
for (int j = 1; j <= len && i * pr[j] <= n; j++) {
vis[pr[j] * i] = 1;
int num = i * pr[j], now = pr[j] - pr[j - 1];
if (now > gap) {
S++;
for (int ex = gap + 1; ex <= now; ex++)
powers[ex] = 1ull * powers[ex - 1] * f[i] % mod;
gap = now;
}
cur = 1ull * cur * powers[now] % mod;
f[num] = 1ull * bsgs1[pr[j]][i % B] * bsgs2[pr[j]][i / B] % mod * cur % mod;
if (i % pr[j] == 0) break;
}
}
fprintf(stderr, "S = %d\n", S);
fprintf(stderr, "time used = %.10f\n", (clock()) / 1. / CLOCKS_PER_SEC);
}

实验数据:

  • \(n=10^7\):\(\text{0.188s}\);
  • \(n=10^8\):\(\text{1.816s}\)。

\(\mathcal O(n \log \ln n)\) 的实现(即 prime gap 每次暴力快速幂计算):

const int N = 100000005;
const int SN = ((int)sqrt(N) + 5);
const int mod = 998244353; int qpow(int a, int b) {
int res = 1;
while (b > 0) {
if (b & 1) res = 1ull * res * a % mod;
a = 1ull * a * a % mod, b >>= 1;
}
return res;
} int bsgs1[SN][SN], bsgs2[SN][SN];
bool vis[N];
int f[N], pr[N / 10], len; void sieve(int n) {
f[1] = 1;
const int B = sqrt(n);
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
pr[++len] = i;
f[i] = qpow(i, i);
if (i <= B) {
bsgs1[i][0] = 1;
for (int j = 1; j <= B; j++)
bsgs1[i][j] = 1ull * bsgs1[i][j - 1] * f[i] % mod;
bsgs2[i][0] = 1;
for (int j = 1; j <= B; j++)
bsgs2[i][j] = 1ull * bsgs2[i][j - 1] * bsgs1[i][B] % mod;
}
}
int cur = 1;
for (int j = 1; j <= len && i * pr[j] <= n; j++) {
vis[pr[j] * i] = 1;
int num = i * pr[j];
cur = 1ull * cur * qpow(f[i], pr[j] - pr[j - 1]) % mod;
f[num] = 1ull * bsgs1[pr[j]][i % B] * bsgs2[pr[j]][i / B] % mod * cur % mod;
if (i % pr[j] == 0) break;
}
}
fprintf(stderr, "time used = %.10f\n", (clock()) / 1. / CLOCKS_PER_SEC);
}

实验数据:

  • \(n=10^7\):\(\text{0.206s}\);
  • \(n=10^8\):\(\text{2.094s}\)。

\(\mathcal O(n\log n)\) 的实现(每次暴力计算):

const int N = 100000005;
const int mod = 998244353; int qpow(int a, int b) {
int res = 1;
while (b > 0) {
if (b & 1) res = 1ull * res * a % mod;
a = 1ull * a * a % mod, b >>= 1;
}
return res;
} int f[N]; void sieve(int n) {
f[1] = 1;
for (int i = 2; i <= n; i++) f[i] = qpow(i, i);
fprintf(stderr, "time used = %.10f\n", (clock()) / 1. / CLOCKS_PER_SEC);
}

实验数据:

  • \(n=10^7\):\(\text{0.801s}\);
  • \(n=10^8\):\(\text{8.547s}\)。

线性求 $i^i$ 的做法的更多相关文章

  1. noip 2016 提高组题解

    前几天写的那个纯属搞笑.(额,好吧,其实这个也不怎么正经) 就先说说day2吧: T1:这个东西应该叫做数论吧. 然而我一看到就照着样例在纸上推了大半天(然而还是没有看出来这东西是个杨辉三角) 然后就 ...

  2. 2016北京集训测试赛(十七)Problem B: 银河战舰

    Solution 好题, 又是长链剖分2333 考虑怎么统计答案, 我场上的思路是统计以一个点作为结尾的最长上升链, 但这显然是很难处理的. 正解的方法是统计以每个点作为折弯点的最长上升链. 具体的内 ...

  3. 模板库 ~ Template library

    TOC 建议使用 Ctrl+F 搜索 . 目录 小工具 / C++ Tricks NOI Linux 1.0 快速读入 / 快速输出 简易小工具 无序映射器 简易调试器 文件 IO 位运算 Smart ...

  4. luoguP5227 [AHOI2013]连通图(线性基做法)

    题意 神仙哈希做法. 随便找个生成树,给每个非树边赋一个值,树边的值为所有覆盖它的边的值得异或和. 删去边集使得图不联通当且即当边集存在一个子集异或和为0,可以用线性基. 证明的话好像画个图挺显然的 ...

  5. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法

    洛谷题面传送门 一个线性做法. \(n\log n\) 解法可以戳这里查看 首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t ...

  6. 「ARC 139F」Many Xor Optimization Problems【线性做法,踩标】

    「ARC 139F」Many Xor Optimization Problems 对于一个长为 \(n\) 的序列 \(a\),我们记 \(f(a)\) 表示从 \(a\) 中选取若干数,可以得到的最 ...

  7. BZOJ 5093[Lydsy1711月赛]图的价值 线性做法

    博主曾更过一篇复杂度为$O( k· \log k)$的多项式做法在这里 惊闻本题有$ O(k)$的神仙做法,说起神仙我就想起了于是就去学习了一波 幂与第二类斯特林数 推导看这里 $$ x^k=\sum ...

  8. 「TJOI / HEOI2016」求和 的一个优秀线性做法

    我们把\(S(i, j)j!\)看成是把\(i\)个球每次选择一些球(不能为空)扔掉,选\(j\)次后把所有球都扔掉的情况数(顺序有关).因此\(S(i, j)j! = i![x^i](e^x - 1 ...

  9. Header,Tab,ListView三个在线性布局中,ListView向上滑动时,Tab标签悬停在顶部,然后Header向上滑出去,这个效果的做法

    效果如图: 这个效果可以用一个框架来做,首先在网上搜关键字,然后搜索的结果在这里:http://stackoverflow.com/questions/20906964/viewpager-with- ...

随机推荐

  1. java中匿名内部类的匿名构造函数是怎么用的

    java中匿名内部类的匿名构造函数是怎么用的下面的例子说明匿名内部类的匿名构造函数的用法 例2.7.2_0interface FigureMark_to_win {    void whoAmI(); ...

  2. 子线程中如何修改ui界面

    1.Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view包 ...

  3. Linux环境下Eclipse中快捷键不起作用

    在window->Preferences->general->keys中, 找到 content asist 修改下边值 Binding 改成 Alt+/ When 改为 Editi ...

  4. 深入研究const(es6特性)

    const  申明常量 var str = 'es6' console.log(window.str) // es6 属于顶层对象window const不属于顶层对象window const str ...

  5. Typecho文章设置永久链接

    说明 想要给Typecho文章一个独立的url,或按照自己的格式来 这时候我们就要设置永久链接 Typecho设置文章永久链接 设置伪静态 伪静态设置要取决于是nginx还是apache,详情请参考& ...

  6. 洛谷 P1162 填涂颜色 DFS

    P1162 填涂颜色 https://www.luogu.com.cn/problem/P1162 qaq搜索好抽象啊,蒟蒻表示难以理解,搞半天才做出来一道题,很挫败www 思路 染色法.找墙壁外的连 ...

  7. SQL语言学习-DQL条件查询

    条件查询 1. where子句后跟条件 2. 运算符 * > .< .<= .>= .= .<> * BETWEEN...AND * IN( 集合) * LIKE: ...

  8. 2021.07.19 P2294 狡猾的商人(差分约束)

    2021.07.19 P2294 狡猾的商人(差分约束) [P2294 HNOI2005]狡猾的商人 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.差分约束最长路与最短 ...

  9. python中一些列表知识

    列表 序列是 Python 中最基本的数据结构. 序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推. Python 有 6 个序列的内置类型,但最常见的是列表和 ...

  10. python基础练习题(题目 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少)

    day13 --------------------------------------------------------------- 实例021:猴子偷桃 题目 猴子吃桃问题:猴子第一天摘下若干 ...