如果一个数 a a a除以另一个数 b b b的余数为0,即 a % b a\%b a%b == 0, 则 b b b是 a a a的约数。
时间复杂度 O ( n ) O(\sqrt n) O(n)
一个数的约数是成对出现的,并且一个在 n \sqrt n n左边,一个在右边,所以只需要枚举到 n \sqrt n n即可。
void get_divisors(int x)
{
vector<int> res;
for (int i = 1; i <= x / i; i ++ )
{
if (x % i == 0)
{
res.push_back(i);
if (i != x / i) res.push_back(x / i);
}
}
sort(res.begin(), res.end());
for (auto item : res) cout << item << " ";
cout << endl;
return ;
}
有一个数 N N N,可以进行质因数分解: N = p 1 α 1 p 2 α 2 p 3 α 3 . . . p k α k N=p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}...p_k^{\alpha_k} N=p1α1p2α2p3α3...pkαk。任何一个约数可以表示成 d = p 1 β 1 p 2 β 2 p 3 β 3 . . . p k β k β i ≤ α i d=p_1^{\beta_1}p_2^{\beta_2}p_3^{\beta_3}...p_k^{\beta_k}\beta_i \leq \alpha_i d=p1β1p2β2p3β3...pkβkβi≤αi。 β 1 \beta_1 β1有 α 1 + 1 \alpha_1 + 1 α1+1种选法, β 2 \beta_2 β2有 α 2 + 1 \alpha_2 + 1 α2+1种选法, β k \beta_k βk有 α k + 1 \alpha_k+ 1 αk+1种选法,所以约数个数一共有 ( α 1 + 1 ) ( α 2 + 1 ) ( α 3 + 1 ) . . . ( α k + 1 ) (\alpha_1 + 1)(\alpha_2 + 1)(\alpha_3 + 1)...(\alpha_k + 1) (α1+1)(α2+1)(α3+1)...(αk+1)种。
unordered_map<int, int> primes;
while(n--){
cin >> x;
for(int i = 2;i <= x/i; ++i){
while(x % i == 0){
x /= i;
primes[i] ++;
}
}
if(x > 1) primes[x] ++;
}
for(auto i : primes) ans = ans*(i.second + 1) % mod;
cout << ans;
有一个数 N N N,可以进行质因数分解: N = p 1 α 1 p 2 α 2 p 3 α 3 . . . p k α k N=p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}...p_k^{\alpha_k} N=p1α1p2α2p3α3...pkαk。任何一个约数可以表示成 d = p 1 β 1 p 2 β 2 p 3 β 3 . . . p k β k β i ≤ α i d=p_1^{\beta_1}p_2^{\beta_2}p_3^{\beta_3}...p_k^{\beta_k}\beta_i \leq \alpha_i d=p1β1p2β2p3β3...pkβkβi≤αi。约数之和为 ( 1 + p 1 1 + p 1 2 + . . . + p 1 α 1 ) ( 1 + p 2 1 + p 2 2 + . . . + p 2 α 2 ) . . . ( 1 + p k 1 + p k 2 + . . . + p k α k ) (1+p_1^1+p_1^2+...+p_1^{\alpha_1})(1+p_2^1+p_2^2+...+p_2^{\alpha_2})...(1+p_k^1+p_k^2+...+p_k^{\alpha_k}) (1+p11+p12+...+p1α1)(1+p21+p22+...+p2α2)...(1+pk1+pk2+...+pkαk)。
unordered_map<int, int> primes;
while (n -- )
{
int x;
cin >> x;
for (int i = 2; i <= x / i; i ++ )
while (x % i == 0)
{
x /= i;
primes[i] ++ ;
}
if (x > 1) primes[x] ++ ;
}
LL res = 1;
for (auto p : primes)
{
LL a = p.first, b = p.second;
LL t = 1;
while (b -- ) t = (t * a + 1) % mod;
res = res * t % mod;
}
cout << res << endl;
求两个正整数 a a a 和 b b b 的 最大公约数 d d d
则有 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b) = gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
证明:
设 a % b = a − k ∗ b a\%b = a - k*b a%b=a−k∗b 其中 k = a / b k = a/b k=a/b(向下取整)
若 d d d是 ( a , b ) (a,b) (a,b)的公约数 则知 d ∣ a d|a d∣a 且 d ∣ b d|b d∣b 则易知 d ∣ a − k ∗ b d|a-k*b d∣a−k∗b 故 d d d也是 ( b , a % b ) (b,a\%b) (b,a%b) 的公约数
若 d d d是 ( b , a % b ) (b,a\%b) (b,a%b)的公约数 则知 d ∣ b d|b d∣b 且 d ∣ a − k ∗ b d|a-k*b d∣a−k∗b 则 d ∣ a − k ∗ b + k ∗ b = d ∣ a d|a-k*b+k*b = d|a d∣a−k∗b+k∗b=d∣a 故而 d d d同时整除 a a a和 b b b 所以 d d d也是 ( a , b ) (a,b) (a,b)的公约数
因此 ( a , b ) (a,b) (a,b)的公约数集合和 ( b , a % b ) (b,a\%b) (b,a%b)的公约数集合相同 所以他们的最大公约数也相同
时间复杂度 O ( l o g ( a + b ) ) O(log(a+b)) O(log(a+b))
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏.
贝茜让 N N N 头奶牛(编号 1 1 1 到 N N N)坐成一个圈。除了 1 1 1 号与 N N N 号奶牛外,i 号奶牛与 i − 1 i−1 i−1 号和 i + 1 i+1 i+1 号奶牛相邻, N N N 号奶牛与 1 1 1 号奶牛相邻。
农夫约翰用很多纸条装满了一个桶,每一张纸条中包含一个 到 1000000 之间的数字。
接着每一头奶牛 i i i 从桶中取出一张纸条,纸条上的数字用 A i A_i Ai 表示。
所有奶牛都选取完毕后,每头奶牛轮流走上一圈,当走到一头奶牛身旁时,如果自己手中的数字能够被该奶牛手中的数字整除,则拍打该牛的头。
牛们希望你帮助他们确定,每一头奶牛需要拍打的牛的数量。
即共有 N N N 个整数 A 1 , A 2 , … , A N A_1,A_2,…,A_N A1,A2,…,AN,对于每一个数 A i A_i Ai,求其他的数中有多少个是它的约数。
输入格式
第一行包含整数 N N N。
接下来 N N N 行,每行包含一个整数 A i A_i Ai。
输出格式
共 N N N 行,第 i i i 行的数字为第 i i i 头牛需要拍打的牛的数量。
数据范围
1 ≤ N ≤ 1 0 5 , 1≤N≤10^5, 1≤N≤105,
1 ≤ A i ≤ 1 0 6 1≤Ai≤10^6 1≤Ai≤106
输入样例:
5
2
1
2
3
4
输出样例:
2
0
2
1
3
如果直接采用暴力的做法,时间复杂度为 O ( N 2 ) ( N 为数据规模 ) O(N^2)(N为数据规模) O(N2)(N为数据规模)。
考虑对于每一个数,事先存储下来,并且,并且枚举他们的倍数,可以把时间复杂度降到 O ( M + M / 2 + M / 3 + . . . + M / N ) = O ( M l o g N ) ( M 为 A i 上限 ) O(M+M/2+M/3+...+M/N)=O(MlogN)(M为A_i上限) O(M+M/2+M/3+...+M/N)=O(MlogN)(M为Ai上限)。
#include
using namespace std;
const int N = 1000010;
int a[N], sum[N], cnt[N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
cnt[a[i]] ++ ;
}
for (int i = 1; i < N; i ++ )
{
if (!cnt[i]) continue;
for (int j = i; j < N; j += i )
sum[j] += cnt[i];
}
for (int i = 1; i <= n; i ++ )
cout << sum[a[i]] - 1 << endl;
return 0;
}
求方程:
1 x + 1 y = 1 n ! \dfrac{1}{x} + \dfrac{1}{y} = \dfrac{1}{n!} x1+y1=n!1
的正整数解的组数,答案对 1 0 9 + 7 10^9+7 109+7 取模。
输入格式
输入只有一行一个整数,表示 n n n。
输出格式
输出一行一个整数表示正整数解的组数模 1 0 9 + 7 10^9+7 109+7 的值。
输入输出样例 #1
输入 #1
2
输出 #1
3
输入输出样例 #2
输入 #2
1439
输出 #2
102426508
说明/提示
样例 1 解释
共有三个数对 ( x , y ) (x,y) (x,y) 满足条件,分别是 ( 3 , 6 ) , ( 4 , 4 ) (3,6),(4,4) (3,6),(4,4) 和 ( 6 , 3 ) (6,3) (6,3)。
数据规模与约定
1 x + 1 y = 1 n ! \dfrac{1}{x} + \dfrac{1}{y} = \dfrac{1}{n!} x1+y1=n!1
( x + y ) n ! = x y (x+y)n!=xy (x+y)n!=xy
x = y n ! y − n ! = ( y − n ! + n ! ) n ! y − n ! = n ! + ( n ! ) 2 y − n ! x=\dfrac{yn!}{y-n!}=\dfrac{(y-n!+n!)n!}{y-n!}=n!+\dfrac{(n!)^2}{y-n!} x=y−n!yn!=y−n!(y−n!+n!)n!=n!+y−n!(n!)2
同时又因为 y > n ! y>n! y>n!,所以 y − n ! y-n! y−n!一定 > 0 >0 >0,本问题可以转换为求 ( n ! ) 2 (n!)^2 (n!)2的约数个数。
#include
using namespace std;
const int N = 1000010;
const int mod = 1e9 + 7;
typedef long long ll;
int prime[N];
bool st[N];
int n, cnt = 0;
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) prime[cnt ++ ] = i;
for (ll j = 0; prime[j] * i <= n; j ++ )
{
st[i * prime[j]] = 1;
if (i % prime[j] == 0)break;
}
}
}
int main()
{
cin >> n;
ll res = 1;
init(n);
for(int i = 0; i < cnt; i ++ )
{
int p = prime[i];
ll s = 0;
for (ll j = p; j <= n; j *= p) s += n / j;
res = res * (2 * s + 1) % mod;
}
cout << res;
return 0;
}
对于任何正整数 x x x,其约数的个数记作 g ( x ) g(x) g(x)。例如 g ( 1 ) = 1 g(1)=1 g(1)=1, g ( 6 ) = 4 g(6)=4 g(6)=4。
如果某个正整数 x x x 满足: ∀ 0 < i < x \forall 0 \lt i \lt x ∀0<i<x,都有 g ( x ) > g ( i ) g(x) \gt g(i) g(x)>g(i),则称 x x x 为反质数。例如,整数 1 , 2 , 4 , 6 1,2,4,6 1,2,4,6 等都是反质数。
现在给定一个数 N N N,你能求出不超过 N N N 的最大的反质数么?
输入格式
一个数 N N N。
输出格式
不超过 N N N 的最大的反质数。
输入输出样例 #1
输入 #1
1000
输出 #1
840
说明/提示
1 ≤ N ≤ 2 × 1 0 9 1 \leq N \leq 2 \times 10^9 1≤N≤2×109
三个关键点:
1.对于反素数分解质因数,一定满足其中大的质数的次数一定不大于前面小的次数的质数,因为如果后者次数大,我们就可以交换前后两者的次数,这样结果不变,但是会得到更小的数。
2.分解质因数后的质数只会是 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 21 , 23 2,3,5,7,11,13,17,19,21,23 2,3,5,7,11,13,17,19,21,23中的数,因为如果再多一个质数,乘积就大于 N N N了。
3.次数之和一定不超过30,因为 2 31 > 2 ∗ 1 0 9 2^{31}>2*10^9 231>2∗109。
根据以上性质进行深搜。
#include
using namespace std;
typedef long long ll;
const int N = 2e9 + 10;
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
int maxd, number;
int n;
void dfs(int u, int last, int p, int s)
{
if (s > maxd || (s == maxd && p < number))
{
maxd = s;
number = p;
}
if (u == 9) return ;
for (int i = 1; i <= last; i ++ )
{
if ((ll) p * primes[u] > n) break;
p *= primes[u];
dfs(u + 1, i, p, s * (i + 1));
}
return ;
}
int main()
{
cin >> n;
// 枚举到哪一个素数,当前素数最大取几个,当前数,当前约数个数
dfs(0, 30, 1, 1);
cout << number << endl;
return 0;
}
Hanks 博士是 BT(Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数 c 1 c_1 c1 和 c 2 c_2 c2 的最大公约数和最小公倍数。现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数 a 0 , a 1 , b 0 , b 1 a_0,a_1,b_0,b_1 a0,a1,b0,b1,设某未知正整数 x x x 满足:
x x x 和 a 0 a_0 a0 的最大公约数是 a 1 a_1 a1;
x x x 和 b 0 b_0 b0 的最小公倍数是 b 1 b_1 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x x x。但稍加思索之后,他发现这样的 x x x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x x x 的个数。请你帮助他编程求解这个问题。
输入格式
第一行为一个正整数 n n n,表示有 n n n 组输入数据。接下来的$ n$ 行每行一组输入数据,为四个正整数 a 0 , a 1 , b 0 , b 1 a_0,a_1,b_0,b_1 a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证 a 0 a_0 a0 能被 a 1 a_1 a1 整除, b 1 b_1 b1 能被 b 0 b_0 b0 整除。
输出格式
共 n n n 行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 x x x,请输出 0 0 0,若存在这样的 x x x,请输出满足条件的 x x x 的个数;
输入输出样例 #1
输入 #1
2
41 1 96 288
95 1 37 1776
输出 #1
6
2
说明/提示
【样例解释】
第一组输入数据, x x x 可以是 9 , 18 , 36 , 72 , 144 , 288 9,18,36,72,144,288 9,18,36,72,144,288,共有 6 6 6 个。
第二组输入数据, x x x 可以是 48 , 1776 48,1776 48,1776,共有 2 2 2 个。
【数据范围】
如果采用暴力方法,即枚举 b 1 b_1 b1的每个约数,再判断这个约数是否满足条件的话,时间复杂度为 O ( T b 1 l o g b 1 ) O(T\sqrt{b_1}logb_1) O(Tb1logb1)。
考虑先求出 N N N以内的所有素数,对于每个 b 1 b_1 b1,分解质因数,dfs得到所有约数,再对于每个约数判断是否合法。
时间复杂度:
1.预处理所有的约数 O ( N ) O(N) O(N)
2.分解质因数,因为已经得到了所有的质数,所以枚举质数即可,不需要枚举到 b 1 \sqrt{b_1} b1,因此时间复杂度为 O ( T ∗ b 1 / l n b 1 ) O(T*\sqrt{b_1}/ln\sqrt{b_1}) O(T∗b1/lnb1)
3.平均每个数约数的个数为 l o g b 1 logb_1 logb1,做判断的时间复杂度为 l o g b 1 logb_1 logb1,因此对于每个约数判断是否合法的时间复杂度总和为 O ( T ∗ ( l o g b 1 ) 2 ) ) O(T*(logb_1)^2)) O(T∗(logb1)2))
#include
#include
#include
using namespace std;
#define N 500010
struct Data{
int p, c;
}factor[N];
int prime[N];
bool st[N];
int divider[N];
typedef long long ll;
//cnt 记录素数个数,cnt2记录一个数可以分解为的不同质因子个数
//cnt3记录一个数的约数个数
int n, cnt = 0, cnt2 = 0, cnt3 = 0;
int a0, a1, b0, b1;
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i])prime[cnt ++ ] = i;
for (int j = 0; prime[j] * i <= n; j ++ )
{
st[i * prime[j]] = 1;
if (i % prime[j] == 0)break;
}
}
}
void divide(int x)
{
cnt2 = 0;
for (int i = 0; prime[i] <= sqrt(x); i ++ )
{
int p = prime[i];
if (x % p == 0)
{
int s = 0;
while (x % p == 0)
{
s += 1;
x /= p;
}
factor[cnt2 ++ ] = {p, s};
}
}
if(x > 1) factor[cnt2 ++ ] ={x, 1};
}
void dfs(int u, int p)
{
if (u == cnt2)
{
divider[cnt3 ++ ] = p;
return ;
}
for (int i = 0; i <= factor[u].c; i ++ )
{
dfs(u + 1, p);
p *= factor[u].p;
}
return ;
}
int gcd(int x, int y)
{
return y ? gcd(y, x % y) : x;
}
ll lcm(int x, int y)
{
return (ll) x * y / gcd(x, y);
}
int main()
{
init(N - 1);
cin >> n;
while(n -- )
{
cin >> a0 >> a1 >> b0 >> b1;
divide(b1);
cnt3 = 0;
dfs(0, 1);
int res = 0;
for (int i = 0; i < cnt3; i ++ )
{
if(gcd(a0, divider[i]) == a1 && lcm(b0, divider[i]) == b1)
res ++ ;
}
cout << res << endl;
}
return 0;
}