引理:对所有素数 p 和 所有整数 a,b,如果 p | ab,则 p | a 或 p | b (或两者都成立)
证明:采用反证法。假设 p | ab,但 p ∤ a 且 p ∤ b。故gcd(a,p)= 1,gcd(b,p)= 1,故gcd(ab,p) = 1,而 gcd(ab,p) = p,矛盾,原命题成立。
定理:如果素数 p ∣ a 1 a 2 a 3 . . . a r p | a _1 a_2a_3...a_r p∣a1a2a3...ar,则 p ∣ a 1 p | a_1 p∣a1 或 p ∣ a 2 p | a_2 p∣a2…或 p ∣ a r p | a_r p∣ar至少一个成立
由上面这个定理我们发现:
①数n可以以某种方式分解成素数乘积
②仅有唯一的因数分解(不考虑因数重排)
任何一个大于1的整数n 都可以分解成若干个素因数的连乘积,如果不计各个素因数的顺序,那么这种分解是惟一的。
n = ∏ i = 1 r p i e i n = \prod_{i=1}^r p_i^{e_i} n=i=1∏rpiei
e i e_i ei为正整数, p i p_i pi为互不相同的素数。
证明:唯一分解定理
给你一个数n,如何将他拆分成素数的乘积呢?
直接枚举因子然后把当前因子全部除尽即可,时间复杂度 O ( n ) O(\sqrt n) O(n)
int e[N],p[N];
void divide(int n)
{
int cnt = 0;
for(int i=2; i*i<=n; i++)
{
if(n%i == 0)
{
p[++cnt] = i,e[cnt] = 0;
while(n % i == 0)
{
n /= i;
e[cnt]++;
}
}
}
if(n > 1)
p[++cnt] = n,e[cnt]=1;
for(int i = 1;i <= cnt; ++ i)
cout << p[i] << "^" << e[i] << endl;
}
一种大数(如n>1e18)分解的随机算法
有空再细写
将n分解过后, n = p 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p r e r n=p_1^{e_1}*p_2^{e_2}*...*p_r^{e_r} n=p1e1∗p2e2∗...∗prer ,n的因子一定是 p i p_i pi的组合,且每个组合的选择有 e i + 1 e_i+1 ei+1个,因此因子个数为 ∏ i = 1 r ( e i + 1 ) \prod_{i=1}^r{(e_i+1)} ∏i=1r(ei+1)
例题:
给定x,y(x,y<231 )问xy的因子数mod10007是多少?
如果强行计算,xy已经是天文数字了,所以我们考虑将他分解为素数的乘积
x y = ( p 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p r e r ) y = p 1 y e 1 ∗ p 2 y e 2 ∗ . . . ∗ p r y e r x^y=(p_1^{e_1}*p_2^{e_2}*...*p_r^{e_r})^y=p_1^{ye_1}*p_2^{ye_2}*...*p_r^{ye_r} xy=(p1e1∗p2e2∗...∗prer)y=p1ye1∗p2ye2∗...∗pryer
答案即为 ∏ i = 1 r ( y e i + 1 ) m o d 10007 \prod_{i=1}^r{(ye_i+1)} mod10007 ∏i=1r(yei+1)mod10007
设 S ( n ) S(n) S(n)为因子和,考虑每个 p i , S ( n ) = ( p i 0 + p i 1 + . . . + p i e i ) ∗ ( S ( 剩 余 ) ) p_i,S(n)=(p_i^{0}+p_i^{1}+...+p_i^{e_i}) *(S(剩余)) pi,S(n)=(pi0+pi1+...+piei)∗(S(剩余)),由等比数列求和公式得知因子和为 ∏ i = 1 r p i e i + 1 − 1 p i − 1 \prod_{i=1}^r\frac{p_i^{e_i+1}-1}{p_i-1} ∏i=1rpi−1piei+1−1
例题:
约数之和
思路:与上题类似,要注意的是分数取模的时候,如果p-1 ≡ 0(mod9901),则不存在乘法逆元,p ≡ 1(mod9901),故(1+p+p2 +…+pe*b ) = (1+1+1+…+1) = e*b+1,否则用乘法逆元就可以解决。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 50000005
#define mod 9901
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define PII pair<int,int>
#define mp make_pair
using namespace std;
const int INF = 1000 * 1000 + 5;
typedef long long ll;
//freopen("D:\\in.txt","r",stdin);
//freopen("D:\\in.txt","w",stdout);
using namespace std;
int p[N],c[N];
int tot;
void divide(ll n)
{
for(int i=2; i*i<=n; i++)
{
if(n%i == 0)
{
p[++tot] = i;
c[tot] = 0;
while(n%i==0)
{
n/=i;
c[tot]++;
}
}
}
if(n>1)
{
p[++tot] = n;
c[tot] = 1;
}
}
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans = (ans*a)%mod;
a = (a*a)%mod;
b >>= 1;
}
return ans;
}
int main()
{
ll a,b;
scanf("%lld%lld",&a,&b);
if(a==0)
{
printf("0\n");
return 0;
}
divide(a);
ll ans=1;
for(int i=1; i<=tot; i++)
{
if((p[i]-1)%mod == 0)
{
ans = (b*c[i]+1)%mod * ans %mod;
continue;
}
ll x = qpow(p[i],(ll)b*c[i]+1);//分子
x = (x-1+mod) %mod;
ll y = p[i]-1;//分母
y = qpow(y,mod-2);//费马小定理求逆元
ans = ans * x % mod * y % mod;
}
printf("%lld\n",ans);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 1000005
#define mod 998244353
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define PII pair<int,int>
#define mp make_pair
using namespace std;
const int INF = 1000 * 1000 + 5;
typedef long long ll;
//freopen("D:\\in.txt","r",stdin);
//freopen("D:\\in.txt","w",stdout);
using namespace std;
int primes[N],cnt;
bool vis[N];
void shai(int n)
{
vis[1]=vis[0]=1;
for(int i=2; i<=n; i++)
{
if(!vis[i]) primes[cnt++] = i;
for(int j=0; primes[j]*i<=n && j<cnt; j++)
{
vis[primes[j]*i] = 1;
if(i%primes[j]==0) break;
}
}
}
int main()
{
IO;
int n;
cin>>n;
shai(n);
for(int i=0; i<cnt; i++)
{
int p = primes[i];
int s = 0;
for(int j=n; j; j/=p) s += j/p;
cout<<p<<" "<<s<<endl;
}
return 0;
}
变形1:求N!末尾0的个数。
思路:也就是求因子乘积为10的个数,即2,5因子数的最小值,而容易知道5的个数一定比2少,因此计算因子5的个数即可
int ans = 0;
while(n)
{
num += n / 5;
n /= 5;
}
return ans;
类似的要求N!在二进制最低位1出现的位置,也就是求因子2出现的个数
变形2:求N!的因子的因子个数和
思路: N ! = p 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p r e r N!=p_1^{e_1}*p_2^{e_2}*...*p_r^{e_r} N!=p1e1∗p2e2∗...∗prer
p i e i p_i^{e_i} piei的选择有 e i + 1 种 e_i+1种 ei+1种: p i 0 , p i 1 , . . . . . . , p i e 1 p_i^{0},p_i^1,......,p_i^{e_1} pi0,pi1,......,pie1
p i 0 p_i^{0} pi0有1个因子, p i 1 p_i^{1} pi1有2个因子, p i e 1 p_i^{e_1} pie1有 e 1 + 1 e_1+1 e1+1个因子
故对于 p i p_i pi所贡献的因子数即为 ( e i + 1 ) ∗ ( e i + 2 ) 2 \frac{(e_i+1)*(e_i+2)} {2} 2(ei+1)∗(ei+2)
最后再将每一个p的因子数乘起来即是结果了
公式为 ∏ i = 1 r ( e i + 1 ) ∗ ( e i + 2 ) 2 \prod_{i=1}^r\frac{(e_i+1)*(e_i+2)} {2} ∏i=1r2(ei+1)∗(ei+2)
题目链接:Divisors of the Divisors of An Integer(2018-2019 ACM-ICPC, Asia Dhaka Regional ContestC)
《算法竞赛中的初等数论》(一)正文 0x00整除、0x10 整除相关(ACM / OI / MO)(十五万字符数论书)
夜深人静写算法(三)- 初等数论入门