97. 约数之和(分治)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了97. 约数之和(分治)相关的知识,希望对你有一定的参考价值。
97. 约数之和(分治)
求 a b a^b ab的约数和 模 p p p的值。
σ ( a b ) ( m o d p ) \\large \\sigma(a^b)\\pmod{p} σ(ab)(modp)
首先利用算数基本定理:
a b = ( p 1 k 1 p 2 k 2 … p m k m ) b = p 1 k 1 b p 2 k 2 b … p m k m b \\large a^b=(p_1^{k_1}p_2^{k_2}\\dots p_m^{k_m})^b=p_1^{k_1b}p_2^{k_2b}\\dots p_m^{k_mb} ab=(p1k1p2k2…pmkm)b=p1k1bp2k2b…pmkmb
又 σ ( n ) = ( 1 + p 1 + p 1 2 ⋯ + p 1 k 1 ) ( 1 + p 2 + p 2 2 ⋯ + p 2 k 2 ) … ( 1 + p m + p m 2 + ⋯ + p m k m ) = σ ( p 1 k 1 ) σ ( p 2 k 2 ) … σ ( p m k m ) \\sigma(n)=(1+p_1+p_1^2\\dots+p_1^{k_1})(1+p_2+p_2^2\\dots+p_2^{k_2})\\dots (1+p_m+p_m^2+\\dots+ p_m^{k_m})=\\sigma(p_1^{k_1})\\sigma(p_2^{k_2})\\dots \\sigma(p_m^{k_m}) σ(n)=(1+p1+p12⋯+p1k1)(1+p2+p22⋯+p2k2)…(1+pm+pm2+⋯+pmkm)=σ(p1k1)σ(p2k2)…σ(pmkm)
所以我们只需要求出 σ ( p i k i b ) \\large \\sigma(p_i^{k_ib}) σ(pikib)即可。
这个是一个等比数列,有两种方法求解:
1.分治法。
2.公式法。
分治法:令 σ ( p k − 1 ) = f ( p , k ) = p 0 + p 1 + ⋯ + p k − 1 \\sigma(p^{k-1})=f(p,k)=p^0+p^1+\\dots+p^{k-1} σ(pk−1)=f(p,k)=p0+p1+⋯+pk−1
当
k
k
k为偶数时:
f
(
p
,
k
)
=
(
p
0
+
p
1
+
⋯
+
p
k
2
−
1
)
+
(
p
k
2
+
⋯
+
p
k
−
1
)
=
p
k
2
(
1
+
f
(
a
,
k
2
)
)
f(p,k)=(p_0+p_1+\\dots+p^{\\small\\dfrac{k}{2}-1})+(p^{\\small\\dfrac{k}{2}}+\\dots+p_{k-1})=p^{\\small\\dfrac{k}{2}}(1+f(a,\\dfrac{k}{2}))
f(p,k)=(p0+p1+⋯+p2k−1)+(p2k+⋯+pk−1)=p2k(1+f(a,2k))
当 k k k为奇数时,拆掉最后面一项变为偶数情况即可。
代码
// Problem: 约数之和
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/99/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// Date: 2021-07-02 00:16:08
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=9901;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
vector<PII>v;
void init(int n){
for(int i=2;i*i<=n;i++)
if(n%i==0){
PII x;
x.fi=i,x.se=0;
while(n%i==0) x.se++,n/=i;
v.pb(x);
}
if(n>1) v.pb(n,1);
}
ll ksm(ll a,ll n,ll m=mod){
ll ans=1;
while(n){
if(n&1) ans=ans*a%m;
a=a*a%m;以上是关于97. 约数之和(分治)的主要内容,如果未能解决你的问题,请参考以下文章
《算法竞赛进阶指南》-AcWing-97. 约数之和 Sumdiv-题解