约数推导
$$ \begin{align} N = &p_1^{\alpha_1} * p_2^{\alpha_2} *\dots * p_k^{\alpha_k}\\\\ ans = &(\alpha_1+1)(\alpha_2+1)\dots(\alpha_k+1)\\\\ &因为 任何一个 约数 d可以表示成\\\\ d=&p_1^{\beta_1} * p_2^{\beta_2} * \dots * p_k^{\beta_k},0\leq\beta_i\leq\alpha_i\\\\ &每一项的 \beta_i 如果不同,那么约数 d 就不相同(算数基本定理,每个数的因式分解是唯一的)\\\\ &所以n的约数就跟 \beta_i 的选法是一一对应的\\\\ &\beta_1 一共有 0\sim\alpha_1 种选法\\\\ &\beta_2 一共有 0\sim\alpha_2 种选法\\\\ &\dots\\\\ &\beta_k 一共有 0\sim\alpha_k 种选法\\\\ &乘法原理,一共有 ans 个约数 \end{align} $$
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main(){
int n,x;
LL ans = 1;
unordered_map<int,int> hash;
cin >> n;
while(n--){
cin >> x;
for(int i = 2;i <= x/i; ++i){
while(x % i == 0){
x /= i;
hash[i] ++;
}
}
if(x > 1) hash[x] ++;
}
for(auto i : hash) ans = ans*(i.second + 1) % mod;
cout << ans;
return 0;
}
==你说的太对了 听我说 谢谢你应为有你 温暖了四季==
为什么你的文字会唱歌
数学白痴在线迷茫,做到第四章是数学知识就开始害怕了
迭代器遍历:
而你,我的朋友,才是真正的英雄
迭代器遍历跟这个题解里的遍历各有哪些优缺点啊
为什么要用unordered_map来存储数据?
同问
我现在好像明白了,首先unordered_map是哈希表,该题数据量太大,而哈希表恰好可以提高访问单个数据的效率。同时unordered_map是可以存放pair类型的数据,它的first存储的是质数,他的second存储的是个数,遍历时速度会更快
second应该是次方吧
数的个数不就是数的次方吗?
不用unordered_map来存的话,就找不到某个质因数所对应的指数,那个数学公式就用不了了,
根据primes.first找到该质因数,primes.ssecond就是对应的质因数的指数
for(auto i : hash) ans = ans*(i.second + 1) % mod
为什么每乘一次取一次模,而不是等乘完之后再对这个数取模呢乘法和取余是一样的优先级, 谁在前面就先算谁, 这个就是乘完之后再取模
哦哦~ 懂了,蟹蟹~
我没懂,兄弟能帮我解释下吗T~T
模运算与基本四则运算有些相似,但是除法例外。其规则如下:
(a + b) % p = (a % p + b % p) % p (1)
(a - b) % p = (a % p - b % p ) % p (2)
(a * b) % p = (a % p * b % p) % p (3)
a ^ b % p = ((a % p)^b) % p (4)
先模和后模的结果是一样的,先取模可以保证中间结果不会溢出
你好,这个第四个公式中的^符号是立方吧
不是 是指数的意思
按照乘法取模的运算,在for循环最后应该还得对答案去一次模把
谢谢你
感谢感谢
还是没明白为什么先模和后模是一样,按这个模运算公式将“直接先乘起来再模->进行展开”和“直接先模再乘起来”进行比较好像有点不一样吧,能再解释一下吗
不妨这样看,假设要求(a * b * c) % q,根据题目(a b c均小于q),那么模拟一下,第一轮迭代是ans = a % q,第二轮迭代是ans = ((a % q) * b) % q,也可以写成((a % q) * (b % q)) % q,等价于(a + b) % q,再下一轮迭代为 (((a + b) % q) * c) % q,可以写成(((a + b) % q) * (c % q)) % q,等价于(a + b + c) % q,就是题目要的答案。
for(auto i : hash) ans = ans*(i.second + 1) % mod;
根据模运算规则,最后输出时不应该再取一次模吗
cout << ans%mod <<endl;
感觉都一样把,答案应该相等
同问啊 为什么结果取模或者不取模答案是一样的啊
在每次运算的时候ans都会取模,所以最后的ans是一个取模后的结果
你说的太对了 听我说 谢谢你应为有你 温暖了四季
小学生,哈哈哈哈
这里加不加if,都可以过啊。我觉得这个if有点多余。分解因数,一般也是指分成质数表示的形式吧。我不知道我忽略了什么??
##
听我说 谢谢你应为有你 温暖了四季
加不加if都是分解质因数,本来那个if就不用加
for(int i = 2; i <= n / i; i ++)
本来就是分解质因数的吧,我们只是想要质因数的指数而已大佬,为什么先把这些数的乘积求出来再求约数个数就不对了
会爆数据范围。
懂了
如果每次乘一个数就磨一下,让他不超数据范围可以吗
要求的值是所有数乘积的约数的个数,MOD后数值就不是题目要求的那个数了。
哦哦哦哦哦感谢感谢!!
补充,如果用 __int128 或者高精度,仍然无法通过,因为复杂度过高
p1到pn都是质数吗?
hash已经是关键词了,不可以使用
$\color{#4169E1}{你说的对}$
楼上说的对[doge]
这Latex好漂亮
··· res = (t.second + 1) % mod;···
# 为什么改成=就错了呢
我懂了,不需要回复我了
为什么不能这样写
res *= (t.second + 1) % mod先计算 (t.second + 1) % mod 的结果,再将计算结果乘以 res,然后将结果再次赋值给 res。可能会溢出
一种是全算完再取余最后赋值,这一种是一部分取余再相乘再赋值,所以这一种情况就会溢出啊
res = (res * (t.second + 1)) % mod;
其实写成这样最好,虽然多一个括号,但是优先级这玩意不好把握
ok,谢谢大佬
和你思路差不多,不过我忘记了哈希表可以遍历,又开了个存质数的数组,hh
哥们,我想问一下,hash的first和second值也没说存的是质数还是质数的次数呀,为啥遍历的时候取的是second值
这里求的是约数的个数,题主代码里first存的是对应质数,second存的是对应质数的次数,把每个质数次数加一相乘就是要求的答案。
你这篇题解让我学会了auto,我发现了新大陆,拜谢大佬
各位佬儿,ans = ans*(i.second + 1) % (1e9 + 7)为什么不对呢?
之前我这么写,报的错是1e+7是浮点数型不能被整数除,所以y总定义了int mod = 1e+7
为什么要用hash表啊?起到什么作用了吗?
降低索引时间开销
# 6
大佬们 不是太懂dash[i]是什么意思 正常情况下用map存储pi 那实际算是不是应该是map[pi]+=指数αi吗 怎么突然变成了呀 然后x>1 把dash[x]++又是干什么的呀 很迷惑
因为一个数x最多有一个大于sqrt(x)的质因子,for循环里求的是2到sqrt(x)的质因子,所以要单独考虑是否有,如果有就和for循环里一样的操作
我想问下,这里的约数算上1了吗
当 Bi 都选0时就为1了
我其实有个疑问,就是x的范围不会爆int吗,
所以才会取模