数论模板
一.欧拉筛求素数
for (int i = 2; i <= n; i++)
{
if (!pri[i])
ans[++tot] = i;
for (int j = 1; (j <= tot) && (i * ans[j] <= n); j++)
{
pri[i * ans[j]] = 1;
if (i % ans[j] == 0)
break;
}
}
二.欧拉函数
#include <bits/stdc++.h>
#define ll long long
const int N = 1e5 + 5;
ll read()
{
ll x=0;int f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int phi[N],p[N],cnt,E[N],pri[N];
int getphi(int n)//针对一个数求欧拉函数
//原理:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
{
int ans=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
ans=ans/i*(i-1);
while (n%i==0) n/=i;
}
}
if (n) ans=ans/n*(n-1);
return ans;
}
int getphi2(int n)//打表,但较为暴力
{
for (int i=2;i<=n;i++)
{
if (!E[i])
{
for (int j=i;j<=n;j+=i)
{
if (!E[j]) E[j]=j;
E[j]=E[j]/i*(i-1);
}
}
}
return E[n];
}
int getphi3(int n)//用欧拉筛法同时求出素数和欧拉函数
//若a为素数,b%a==0,phi[a*b]=phi[b]*a
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!pri[i])//是素数
{
p[++cnt]=i;
phi[i]=i-1;
}
for (int j=1;j<=cnt&&p[j]*i<=n;j++)
{
pri[p[j]*i]=1;
if (i%p[j]==0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else phi[i*p[j]]=phi[i]*(p[j]-1);//a,b互质,欧拉函数为积性函数,phi[a*b]=phi[a]*phi[b]
}
}
return phi[n];
}
int main()
{
int n=read();
int a=getphi(n);
int b=getphi2(n);
int c=getphi3(n);
printf("%d %d %d",a,b,c);
return 0;
}
三,欧拉筛求约数个数和
#include<bits/stdc++.h>//求1~n的约数个数的和
using namespace std;
#define N 1000010
#define ll long long
ll ans;
int n,t[N],e[N],pri[N],pd[N],cnt;
void oula(int n)//t[i]:i的约数个数
{ //e[i]:i的最小质因子的次数,即pmin^k的k
t[1]=1;
for (int i=2;i<=n;i++)
{
if (!pd[i])
{
pri[++cnt]=i;
t[i]=2;
e[i]=1;
}
for (int j=1;i*pri[j]<=n&&j<=cnt;j++)
{
pd[i*pri[j]]=1;
if (i%pri[j]==0)
{
t[i*pri[j]]=t[i]/(e[i]+1)*(e[i]+2);//公式:n=p1^k1 * p2^k2 * p3^k3 ……
//则n的约数个数为(k1+1)*(k2+1)*(k3+1)……
//k1的次数(即e[i*pri[j]])更新为k1+1
e[i*pri[j]]=e[i]+1;
break;
}
else
{
t[i*pri[j]]=t[i]*2;//t为积性函数
e[i*pri[j]]=1;
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
oula(n);
for (int i=1;i<=n;i++)
ans+=t[i];
cout<<ans;
}
四,线性筛求约数和
#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
ll ans;
int n,t[N],e[N],pri[N],pd[N],cnt;
void oula(int n)//t[i]:i的约数和
{ //e[i]:i的约数中,不能被i的最小质因子整除的约数的 和
t[1]=1;e[1]=1;
for (int i=2;i<=n;i++)
{
if (!pd[i])
{
pri[++cnt]=i;
t[i]=i+1;
e[i]=1;
}
for (int j=1;i*pri[j]<=n&&j<=cnt;j++)
{//令S表示i的约数集,S’表示i的约数翻pj倍后的数的集合
pd[i*pri[j]]=1;
if (i%pri[j]==0)//如果i是pj的倍数,那么S和S’必有交集T,T=S中pj的倍数
{//那么t[i*pj]=S+S'-T=S'+S-T=t[i]*pj+e[i]
t[i*pri[j]]=t[i]*pri[j]+e[i];
e[i*pri[j]]=e[i];
break;
}
else
{
t[i*pri[j]]=t[i]*(pri[j]+1);//积性函数
//也可以证明:S∩S’=∅,则S和S’中无重复元素
//t[i*pj]=S+S'=t[i]+t[i]*pj=t[i]*(pj+1)
e[i*pri[j]]=t[i];
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
oula(n);
for (int i=1;i<=n;i++)
ans+=t[i];
cout<<ans;
}
五,快速幂
ll b,n,k,ans=1;
int main()
{
b=read();n=read();k=read();
b%=k;
while(n)
{
if(n&1)ans=(ans*b)%k;
n>>=1;
b=(b*b)%k;
}
printf("%I64d",ans);
return 0;
}
六,逆元
- 费马小定理求逆元
ll qpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res % mod;
}
// 费马小定理 —— a在模p意义下的逆元
ll Inv(ll a, ll p) { return qpow(a, p - 2); }
2.扩展欧几里得求逆元
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y) //扩展欧几里得算法
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
ll t = exgcd(b, a % b, x, y);
ll tmp = x;
x = y;
y = tmp - a / b * x;
return t;
}
ll Inv(int a, int mod) //求a在mod下的逆元,不存在逆元返回-1
{
ll x, y;
ll d = exgcd(a, mod, x, y);
return d == 1 ? (x%mod+ mod) % mod : -1; //x可能是负数,转化成正数
}
七,中国剩余定理
#include<bits/stdc++.h>
#define inf 1000000000
#define ll long long
#define N 500010
#define lson rt<<1
#define rson rt<<1|1
#define mo 999911659
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n;
ll x,y,yu[20],pri[20],M=1,ans;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if (b==0) {x=1,y=0;return a;}
ll g=exgcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;
return g;
}
int main()
{
int n=read();
for (int i=1;i<=n;i++)
{
pri[i]=read();M*=pri[i];
yu[i]=read();
}
for (int i=1;i<=n;i++)
{
ll tmp=M/pri[i];
exgcd(tmp,pri[i],x,y);
ans=(ans+yu[i]*tmp*x+M)%M;
}
printf("%lld",(ans+M)%M);
return 0;
}
八,Lucas定理
#include<bits/stdc++.h>//求C(n+m,m)
using namespace std;
#define re register int
#define ull unsigned long long
#define ll long long
#define INF 0x3f3f3f3f
#define N 200009
#define lson rt<<1
#define rson rt<<1|1
#define ne e[i].to
#define mo 998244353
#define lowbit(x) (x)&(-(x))
void FRE(){freopen("journalist.in","r",stdin);freopen("journalist.out","w",stdout);}
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();}
return x*f;
}
typedef pair<int,ll>P;
int n,m,p;
ll fac[100010];
ll ksm(ll a,int b)
{
ll res=1;
while (b)
{
if (b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
ll cal(int a,int b)
{
if (a<b) return 0;if (!b) return 1;
return fac[a]*ksm(fac[b],p-2)%p*ksm(fac[a-b],p-2)%p;
}
ll lucas(int x,int y)
{
if (!y) return 1;if (x<y) return 0;
return lucas(x/p,y/p)*cal(x%p,y%p)%p;
}
int main()
{
int T=read();
while (T--)
{
n=read(),m=read(),p=read();
fac[0]=1;
for (int i=1;i<=100003;i++) fac[i]=fac[i-1]*i%p;
printf("%lld\n",lucas(n+m,m));
}
return 0;
}