Euler函数与Euler定理
欧拉函数与欧拉定理
证明&结论
https://www.cnblogs.com/lhm-/p/12229648.html
欧拉定理
容斥原理求欧拉函数(了解)
1、如果 i % p == 0 ,那么 phi (i*p) = phi (i) * p。
显然,与 i 互质的每一个数都与 i*p 互质。
2、如果 i % p != 0 , 那么 phi (i*p) = phi (i) * (p-1) 。
因为 i 与 p 互质,根据积性函数的性质,得 phi(i*p) = phi(i) * phi(p)。
又因为 p 是质数,所以 phi(p) = p-1;
暴力筛PHI
int PHI(int x){
int res=x;
for(int i=2;i*i<=x;i++)
if(x%i==0){
res=res/i*(i-1);
while(x%i==0)x/=i;
}
if(x^1)res=res/x*(x-1);
return res;
}
线性筛PHI
void PHI(int x){
phi[1]=1;
for(int i=2;i<=x;i++){
if(!mindiv[i]) mindiv[i]=p[++p[0]]=i,phi[i]=i-1;
for(int j=1;j<=p[0]&&i*p[j]<=x;j++){
mindiv[i*p[j]]=p[j];
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}else phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
}
Longge 的问题
Description
\(\gcd(i, N)(1<=i <=N)\)。
Solution
枚举\(n\)的约数\(k\),令\(s(k)\)为满足\(gcd(m,n)=k,(1<=m<=n)m\)的个数,则\(ans=∑(k*s(k))\) (\(k\)为\(n\)的约数)
因为\(gcd(m,n)=k\),所以\(gcd(m/k,n/k)=1\),于是\(s(k)=phi(n/k)\)
phi可以在根号的时间内求出
#include <cstdio>
#include <iostream>
#define int long long
#define M 10001000
using namespace std;
int n,ans;
int PHI(int x){
int res=x;
for(int i=2;i*i<=x;i++){
if(x%i==0){
res=res/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x^1) res=res/x*(x-1);
return res;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i*i<=n;i++){
if(n%i==0){
ans+=i*PHI(n/i);
if(i*i<n) ans+=(n/i)*PHI(i);
}
}
printf("%lld\n",ans);
return 0;
}
仪仗队
绝了的证明——戳这里
我的大致理解:
要是想要被看到,必须\(gcd(x,y)=1\),
然后我们把图沿着对角线割开,先分析下半部分(显然对角线上除了(2,2)你都看不到),答案乘2
考虑第 \(x\) 列,有多少个\(i\) 与 \(x\) 互素(\(i<x\))——显然phi(i)
#include<bits/stdc++.h>
using namespace std;
#define N 40005
typedef long long ll;
int n;
ll phi[N],ans=3;//(2,2)(1,2)(2,1)特殊点
int main(){
scanf("%d",&n);
if(n==1){
puts("0");
return 0;
}
for(int i=1;i<=n;i++)
phi[i]=i;
for(int i=2;i<=n;i++)
if(phi[i]==i)
for(int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
--n;
for(int i=2;i<=n;i++)
ans+=phi[i]*2;
printf("%d\n",ans);
return 0;
}
奇数国
题意简化:
求 \([1,product ]\) 中有多少数 与 product 互质(φ[product])
线段树维护区间内每个质因子是否出现过,由于只有60个质数,线段树维护二进制60位(状压)即可,并维护区间内的乘积,线段树单点修改,区间求和
不开long long 见祖宗
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=19961993;
const int MAXN=1000005;
#define ls (p<<1)
#define rs (p<<1|1)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
int a,b,c;
int mindiv[300],prime[65];
int inv[65];
int Fpow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
void init(){
for(int i=2;i<=281;i++){
if(!mindiv[i]) prime[++prime[0]]=i,mindiv[i]=i;
for(int j=1;j<=prime[0]&&i*prime[j]<=281&&prime[j]<=mindiv[i];j++)
mindiv[i*prime[j]]=prime[j];
}
for(int i=1;i<=60;i++) inv[i]=Fpow(prime[i],mod-2);
}
int zip(int x){
int res=0;
for(int i=1;i<=60;i++)
if(x%prime[i]==0) res|=(1ll<<(i-1));
return res;
}
struct node{
int l,r;
int sum;
int zy;
}t[MAXN];
void pushup(int p){
t[p].sum=(t[ls].sum*t[rs].sum)%mod;
t[p].zy=(t[ls].zy|t[rs].zy);
}
void build(int l,int r,int p){
t[p].l=l,t[p].r=r;
if(l==r){t[p].sum=3;t[p].zy=(1ll<<1);return;}//棰樻剰鍒濆鍊间负3,3鏄浜屼釜绱犳暟
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
pushup(p);
}
void modify(int pos,int v,int p){
if(t[p].l==t[p].r&&t[p].l==pos){
t[p].sum=v%mod;
t[p].zy=zip(v);
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(pos<=mid) modify(pos,v,ls);
else modify(pos,v,rs);
pushup(p);
}
int query_sum(int p,int l,int r){
if(t[p].l==l&&t[p].r==r) return t[p].sum%mod;
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return query_sum(ls,l,r)%mod;
else if(l>mid) return query_sum(rs,l,r)%mod;
else return (query_sum(ls,l,mid)*query_sum(rs,mid+1,r))%mod;
}
int query_zy(int p,int l,int r){
if(t[p].l==l&&t[p].r==r) return t[p].zy;
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return query_zy(ls,l,r);
else if(l>mid) return query_zy(rs,l,r);
else return query_zy(ls,l,mid)|query_zy(rs,mid+1,r);
}
int cal(int x,int zy){
int res=x;
for(int i=1;i<=60;i++)
if(zy&(1ll<<(i-1)))
res=((res*inv[i]%mod)*(prime[i]-1))%mod;
return res;
}
signed main(){
n=read();
init();
build(1,100000,1);
for(int i=1;i<=n;i++){
a=read(),b=read(),c=read();
if(!a) printf("%lld\n",cal(query_sum(1,b,c),query_zy(1,b,c)));
else modify(b,c,1);
}
return 0;
}
扩展欧拉定理
模板
边读入,边mod
#include<cstdio>
#include<iostream>
using namespace std;
#define int long long
int tmp,phi,a,m,b;
bool flag;
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=(ans*a)%m;
a=(a*a)%m;
b>>=1;
}
return ans;
}
signed main(){
int i;
char c;
scanf("%d%d",&a,&m);
tmp=phi=m;
for(int i=2;i*i<=m;i++){
if(tmp%i==0){
phi=phi/i*(i-1);
while(tmp%i==0) tmp/=i;
}
}
if(tmp>1) phi=phi/tmp*(tmp-1);
while(!isdigit(c=getchar()));
for(;isdigit(c);c=getchar()){
b=b*10+c-'0';
if (b>=phi){
flag=true;
b%=phi;
}
}
if(flag) b+=phi;
printf("%d\n",qpow(a,b));
return 0;
}
上帝与集合的正确用法
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 10001000
using namespace std;
int phi[M],p[1001001],tot;
bool not_p[M];
int PHI(int x){
int res=x;
for(int i=2;i*i<=x;i++)
if(x%i==0){
res=res/i*(i-1);
while(x%i==0)x/=i;
}
if(x^1)res=res/x*(x-1);
return res;
}
int qpow(long long a,long long b,int mod){
long long ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
int solve(int p){
int k=PHI(p);
if(k==1)return 0;
return qpow(2,(solve(k)+k),p);
}
int main(){
int T,mod;
scanf("%d",&T);
while(T--){
scanf("%d",&mod);
printf("%d\n",solve(mod));
}
return 0;
}