欧拉定理
如果 a a a 与 n n n 互质, a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}≡1(\mod \ n) aφ(n)≡1(mod n), φ ( n ) \varphi(n) φ(n) 是 n n n 欧拉函数
威尔逊定理
p
p
p 是质数时,
(
p
−
1
)
!
≡
1
≡
−
1
(
m
o
d
n
)
(p-1)!≡1≡-1(\mod \ n)
(p−1)!≡1≡−1(mod n),
(
p
−
2
)
!
≡
1
(
m
o
d
n
)
(p-2)!≡1(\mod \ n)
(p−2)!≡1(mod n)
等价于,如果
p
p
p 是质数,则
(
(
p
−
1
)
!
+
1
)
%
p
=
0
((p-1)!+1) \ \% \ p \ = 0
((p−1)!+1) % p =0
n
n
n 是质数,
(
n
−
1
)
!
%
n
=
1
(n-1)! \ \% n=1
(n−1)! %n=1
n
n
n 是合数,除
n
=
4
n=4
n=4 以外,
(
n
−
1
)
!
%
n
=
0
(n-1)! \ \% n = 0
(n−1)! %n=0
欧拉函数
就是对于一个正整数
n
n
n,满足
x
<
n
(
x
∈
[
1
,
n
)
x<n(x \in[1,n)
x<n(x∈[1,n) 且
g
c
d
(
n
,
x
)
=
1
gcd(n,x) = 1
gcd(n,x)=1 (包括
1
1
1)的
x
x
x 的个数,记作
φ
(
n
)
φ(n)
φ(n)。
欧拉函数通式:
φ
(
x
)
=
x
∗
∏
i
=
1
n
(
1
−
1
p
i
)
\varphi(x)=x*\prod_{i=1}^{n}(1-\frac{1}{p_i})
φ(x)=x∗i=1∏n(1−pi1)
其中
p
1
,
p
2
…
…
p
n
p1, p2……pn
p1,p2……pn 为
n
n
n 的所有质因数,
n
n
n 是不为
0
0
0 的整数。
φ
(
1
)
=
1
φ(1)=1
φ(1)=1(唯一和
1
1
1 互质的数就是
1
1
1 本身)。
性质:
- 对于质数 p p p, φ ( p ) = p − 1 φ( p) = p - 1 φ(p)=p−1。注意 φ ( 1 ) = 1 φ(1)=1 φ(1)=1
- 若 m , n m,n m,n 互质, φ ( m n ) = φ ( m ) ∗ φ ( n ) φ(mn)=φ(m)*φ(n) φ(mn)=φ(m)∗φ(n)
- 若 p p p 为质数且 i m o d p = 0 i \mod p = 0 imodp=0, 那么 φ ( i ∗ p ) = φ ( i ) ∗ p \varphi(i * p)=\varphi(i) * p φ(i∗p)=φ(i)∗p
- 当 n n n 为奇数时, φ ( 2 n ) = φ ( n ) φ(2n)=φ(n) φ(2n)=φ(n)
- 当 n > 2 n > 2 n>2 时,所有 φ ( n ) φ(n) φ(n) 都是偶数
- 当 n > 6 n > 6 n>6 时,所有 φ ( n ) φ(n) φ(n) 都是合数
- 欧拉定理:对于互质的正整数 a a a 和 n n n ,有 a φ ( n ) ≡ 1 m o d n a^{φ(n)} ≡ 1 \mod n aφ(n)≡1modn
- 费马小定理:若 p p p 是质数,则 a p − 1 ≡ 1 m o d p a^{p-1}≡1 \mod p ap−1≡1modp
- 欧拉定理推论:小于等于 n n n 的数中,与 n n n 互质数的加和为: φ ( n ) ∗ n 2 ( n > 1 ) φ(n)*\frac{n}{2} (n>1) φ(n)∗2n(n>1)
事实上,根据性质
2
,
3
2,3
2,3 ,结合唯一分解定理,我们可以推出一个结论
先说说推导过程
根据唯一分解定理:
n
=
p
1
q
1
p
2
q
2
p
3
q
3
.
.
.
p
n
q
k
n=p_1^{q_1}p_2^{q_2}p_3^{q_3}...p_n^{q_k}
n=p1q1p2q2p3q3...pnqk
结合性质
2
2
2 可以得到
φ
(
n
)
=
φ
(
p
1
q
1
)
φ
(
p
2
q
2
)
φ
(
p
3
q
3
)
.
.
.
φ
(
p
n
q
k
)
\varphi(n)=\varphi(p_1^{q_1})\varphi(p_2^{q_2})\varphi(p_3^{q_3})...\varphi(p_n^{q_k})
φ(n)=φ(p1q1)φ(p2q2)φ(p3q3)...φ(pnqk)
因为
p
1
q
1
=
p
1
∗
p
1
q
1
−
1
p_1^{q_1}=p_1 * p_1^{q_1-1}
p1q1=p1∗p1q1−1,显然符合性质
3
3
3,
p
1
p_1
p1 是质数, 并且
p
1
%
p
1
=
0
p_1 \ \% \ p_1=0
p1 % p1=0
因此
φ
(
p
1
q
1
)
=
φ
(
p
1
q
1
−
1
)
∗
p
1
=
φ
(
p
1
q
1
−
2
)
∗
p
1
2
=
.
.
.
=
φ
(
p
1
)
∗
p
1
q
1
−
1
=
(
p
1
−
1
)
∗
p
1
q
1
−
1
\varphi(p_1^{q_1})=\varphi(p_1^{q_1-1}) * p_1=\varphi(p_1^{q_1-2})*p_1^2=...=\varphi(p_1)*p_1^{q_1-1}=(p_1-1) * p_1^{q_1-1}
φ(p1q1)=φ(p1q1−1)∗p1=φ(p1q1−2)∗p12=...=φ(p1)∗p1q1−1=(p1−1)∗p1q1−1
求一个数的欧拉函数
O
(
s
q
r
t
(
n
)
)
O(sqrt(n))
O(sqrt(n))
code:
//直接求解欧拉函数
int euler(int n){ //返回euler(n)
int res = n, a = n;
for(int i = 2; i * i <= a; ++i){
if(a % i == 0){
res = res / i * (i - 1);//先进行除法是为了防止中间数据的溢出
while(a % i == 0) a /= i;
}
}
if(a > 1) res = res / a * (a - 1);
return res;
}
求1~n每个数的欧拉函数
普通筛法:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
code:
void Init(){
euler[1] = 1;
for(ll i = 2; i < maxn; ++i)
if(!euler[i])
for(ll j = i; j < maxn; j += i){
if(!euler[j]) euler[j] = j;
euler[j] = euler[j] / i * (i - 1);//先进行除法是为了防止中间数据的溢出
}
}
线性筛法:
类似与筛素数,我们在这里利用欧拉函数是积性函数这个性质来筛
φ
(
n
)
φ(n)
φ(n)
这个筛法比上边快好几倍,
m
a
x
n
maxn
maxn 开
1
e
7
1e7
1e7 秒出结果
线性筛法证明
code:
int cnt;
int prime[maxn],phi[maxn];
bool vis[maxn];
void Euler_sieve (int n)
{
phi[1] = 1;
for (int i = 2; i <= maxn - 9; ++i){
if (!vis[i]) prime[++cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && i * prime[j] <= maxn - 9; ++j){
vis[i * prime[j]] = true;
if (i % prime[j] == 0){ phi[i * prime[j]] = phi[i] * prime[j];break;}
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
}
欧拉定理
内容:对任意两个正整数
a
,
n
a,n
a,n,若两者互质,则:
a
φ
(
n
)
≡
1
(
m
o
d
n
)
a^{φ(n)} ≡ 1 (\mod n )
aφ(n)≡1(modn)。
注:作为对比,费马小定理
(
a
p
−
1
≡
1
(
m
o
d
p
)
(a ^{p − 1} ≡ 1 ( \mod \ p )
(ap−1≡1(mod p),其中
p
p
p 为质数),实际上就是欧拉公式的特殊情况。
欧拉降幂(广义欧拉定理)
引出:求解
a
b
m
o
d
p
a^b \mod p
abmodp,对于一定范围内我们可以利用快速幂求解,但是,当b大到一定程度时,利用快速幂这样的算法是无法在给定时间内求解的。
这时我们引入欧拉降幂算法,这个算法的特点就是降低幂方的值而不影响最终结果,使我们解决问题的时间缩短。
欧拉降幂公式:(无互质要求)
a
b
m
o
d
p
=
{
a
b
,
b
<
φ
(
p
)
a
b
m
o
d
φ
(
p
)
+
φ
(
p
)
,
b
>
=
φ
(
p
)
a^b \mod \ p= \begin{cases} a^b,\quad b<\varphi(p) \\ \\ a^{b \mod \varphi(p) + \varphi(p)},\quad b>=\varphi(p) \end{cases}
abmod p=⎩⎪⎨⎪⎧ab,b<φ(p)abmodφ(p)+φ(p),b>=φ(p)
利用欧拉降幂公式求exponial(n)
洛谷模板题
b
b
b 的指数部分可以边乘边模,最后对
a
b
a^b
ab 快速幂即可
i
s
d
i
g
i
t
(
)
isdigit()
isdigit() 函数的作用检查参数是否为十进制数字字符
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a, b, m;
inline ll read(ll m){
register ll x = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)){
x = x * 10 + ch - '0';
if(x >= m) f = 1;
x %= m; ch = getchar();
}
return x + (f == 1 ? m : 0);
}
ll phi(ll x)
{
ll ans = x;
for(ll i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x % i == 0) x /= i;
}
}
if(x > 1) ans = ans / x * (x - 1);
return ans;
}
ll q_pow(ll a, ll n, ll mod){
ll ans = 1;while(n){
if(n & 1) ans=ans*a%mod;n>>=1;a=a*a%mod;
}return ans;
}
int main()
{
cin >> a >> m;
b = read(phi(m));
cout << q_pow(a, b, m);
return 0;
}
上帝与集合的正确用法
题意:
输入一个数
p
p
p,求
f
(
p
)
=
2
2
2
2
.
.
.
m
o
d
p
f(p)=2^{2^{2^{2^{...}}}} \mod p
f(p)=2222...modp,指数部分无限迭代
题意:
求
f
(
p
)
=
2
2
2
2
.
.
.
m
o
d
p
f(p)=2^{2^{2^{2^{...}}}} \mod p
f(p)=2222...modp,指数无限下去
思路:
当
b
>
=
φ
(
p
)
b>=\varphi(p)
b>=φ(p) 时,
a
b
=
a
b
%
φ
(
p
)
+
φ
(
p
)
%
p
a^b=a^{b \ \% \varphi(p) + \varphi(p)} \ \% \ p
ab=ab %φ(p)+φ(p) % p,因为指数无限迭代,显然满足公式
于是我们可以设
f
(
p
)
=
2
2
2
2
.
.
.
m
o
d
p
f(p)=2^{2^{2^{2^{...}}}} \mod p
f(p)=2222...modp,那么有
f
(
1
)
=
0
f(1)=0
f(1)=0
所以
f
(
p
)
=
2
2
2
2
.
.
.
m
o
d
p
=
2
(
2
2
2
.
.
.
%
φ
(
p
)
+
φ
(
p
)
)
m
o
d
p
=
2
f
(
φ
(
p
)
)
+
φ
(
p
)
m
o
d
p
f(p)=2^{ 2^{2^{2^{...}}}} \mod p=2^{(2^{2^{2^{...}}}\% \varphi(p) + \varphi(p))} \mod p =2^{f(\varphi(p)) + \varphi(p)} \mod p
f(p)=2222...modp=2(222...%φ(p)+φ(p))modp=2f(φ(p))+φ(p)modp
接下来就把欧拉定理和快速幂的板子套上就可以了
注意这个题的指数部分始终是无穷大,指数部分
b
b
b 与 模数的
φ
(
p
)
\varphi(p)
φ(p) 的关系是一定的,不用考虑变化。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ph(ll x)
{
ll res=x,a=x;
for(ll i=2;i*i<=x;i++)
{
if(a%i==0)
{
res=res/i*(i-1);
while(a%i==0) a/=i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
ll quick_pow(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
ll f(ll p)
{
if(p == 1) return 0;
ll k = ph(p);
return quick_pow(2, f(k) + k, p);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll p;scanf("%lld",&p);
printf("%lld\n",f(p));
}
return 0;
}
简单数据结构1
思路:
树状数组(区间修改,单点查询)+欧拉降幂
欧拉降幂大约递归
l
o
g
log
log 次
注意指数
b
b
b 和模数
p
p
p 的关系不同时,对其的操作也不同。
考虑到欧拉降幂使用的条件,进行快速幂取模时不能直接用
%
m
o
d
\% \ mod
% mod,应使用下边的取模操作
inline ll Mod(ll x, ll mod)
{
return x < mod ? x : x % mod + mod;
}
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e7 + 9;
ll n, m;
int phi[maxn], cnt, p[maxn];
bitset <maxn> v;
int op, l, r, P;
void init(int n)
{
phi[1] = 1;
for(ll i = 2; i <= n; ++i)
{
if(!v[i]) p[++cnt] = i, phi[i] = i - 1;
for(ll j = 1; j <= cnt && i * p[j] <= n; ++j)
{
v[i * p[j]] = 1;
if(i % p[j] == 0){
phi[i*p[j]] = phi[i] * p[j];break;
}
phi[i*p[j]] = phi[i] * phi[p[j]];
}
}return;
}
ll tr[maxn];
inline void add(int i, ll k){
while(i <= n) tr[i] += k, i += i & (-i);
}
inline ll query(int i, ll ans = 0){
while(i) ans += tr[i], i -= i & (-i);return ans;
}
inline ll Mod(ll x, ll mod){
return x < mod ? x : x % mod + mod;
}
ll q_pow(ll a, ll n, ll mod, ll ans = 1){
a = Mod(a, mod);
while(n){
if(n & 1) ans=Mod(ans*a, mod);a=Mod(a*a,mod);n>>=1;
}return ans;
}
inline ll f(int l, int r, int p)
{
ll b = query(l);
if(p == 1 || l == r) return b < p ? b : b % p + p;
return q_pow(b, f(l + 1, r, phi[p]), p);
}
void work()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i){
ll x;cin >> x;add(i,x);add(i+1,-x);
}
while(m--)
{
cin >> op >> l >> r >> P;
if(op == 1) add(l, P), add(r + 1, -P);
else cout << f(l, r, P) % P << "\n";
}
}
int main()
{
ios::sync_with_stdio(0);
init(2e7);
work();
return 0;
}