扩展欧几里得:解不定方程,求逆元
int extended_gcd(int a, int b, int &x, int &y) {
int r, tmp;
if (b==0) { x = 1; y = 0; return a; }
r = extended_gcd(b, a % b, x, y);
tmp = x; x = y; y = tmp - a / b * y;
return r;
}
求ax ≡ 1 (mod n)的乘法逆元,若不存在,返回-1
long long Inverse(long long a,long long n)
{
long long x,y;
if(extended_gcd(a,n,x,y)==1)return (x+n)%n; else return -1;
}
欧拉函数:
单个欧拉函数:时间复杂度o(sqrt(n))
int euler(int x) //计算φ(x)
{
int i,ans= x, a = x; //找出所有x的质因数
for(i = 2; i*i<= a; i++) //从2讨论到sqrt(n)即可
{
if(a%i == 0) //i为x的质因数
{
ans = ans-ans/i; //φ(x) = x*(1 - 1/p1)*(1 - 1/p2)......
while(a%i == 0) a=a/i; //算术基本定理,抹掉i^1,i^2,i^3....
}
}
if(a > 1) ans =ans - ans/a; //存在大于sqrt(a)的质因子
return ans;
}
线性筛欧拉函数:
void getPhi()
{
int i,j,tot=0;
for(i=2;i<=MaxN;i++) {
if(Mark[i]==false){ Prime[++tot]=i; phi[i]=i-1; }//当 i 是素数时 phi[i]=i-1
for(j=1; j<=tot&&i*Prime[j]<=MaxN; j++) {
Mark[i*Prime[j]]=true;
if(i%Prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j]; break;
} //如果i mod p = 0, 那么 phi[i * p]=p * phi[i]
else phi[i*Prime[j]]=phi[i]*(Prime[j]-1);
}//其实这里Prime[j]-1就是phi[Prime[j]],利用了欧拉函数的积性
}
}
既然写到线性筛了,那就写完。
线性筛质数:
void getPrime()
{
int i,j,tot=0;
for(i=2;i<=MaxN;i++)
{
if(Mark[i]==false)Prime[++tot]=i;
for(j=1; j<=tot&&i*prime[j]<=MaxN; j++) {
Mark[i*Prime[j]]=true; //Prime[j]是合数i*Prime[j]的最小质因数
if(i%Prime[j]==0) break;
} // ↑ 比一个合数大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
}
}
线性筛一个数的因数个数:
void pre(){
int i,j;
d[1]=1;
for(i=2;i<=b;i++){
if(!mark[i]){prime[++tot]=i;temp[i]=1;d[i]=2;}
for(j=1;j<=tot&&i*prime[j]<=b;j++){
mark[i*prime[j]]=true;
if(i%prime[j]==0){
d[i*prime[j]]=d[i]/(temp[i]+1)*(temp[i]+2);
temp[i*prime[j]]=temp[i]+1;
break;
}
else{
d[i*prime[j]]=d[i]*d[prime[j]];
temp[i*prime[j]]=1;
}
}
}
}
二分快速幂:x^y%z;
long long mont(long long x,long long y,long long z){
long long temp=1;
for(x%=z;y;y>>=1,x=(x*x)%z){
if(y&1)temp=(temp*x)%z;
}
return temp;
}
矩阵乘法模板:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define mod m
using namespace std;
typedef long long arr[10][10];
arr a,b,z,ans,map;
long long n,m;
void multiply(arr x,arr y){
memset(z,0,sizeof(z));
for(long long i=1;i<=5;i++){
for(long long j=1;j<=5;j++){
for(long long h=1;h<=5;h++){
z[i][j]=(z[i][j]+x[i][h]*y[h][j]%mod)%mod;
}
}
}
memcpy(x,z,sizeof(z));
}
void mont(long long t){
memset(ans,0,sizeof(ans));
for(long long i=1;i<=5;i++)ans[i][i]=1;
while(t>0){
if(t&1)multiply(ans,b);
t>>=1;
multiply(b,b);
}
}
int main(){
long long i,j;
scanf("%I64d%I64d",&n,&m);
if(n==1){
cout<<"2";return 0;
}
if(n==2){
cout<<"5";return 0;
}
b[1][5]=1;
b[2][2]=1;
b[2][5]=2;
b[3][4]=b[3][5]=1;
b[4][3]=1;
b[5][1]=b[5][2]=b[5][3]=b[5][5]=1;
a[1][1]=1;
a[1][2]=2;
a[1][3]=1;
a[1][4]=1;
a[1][5]=5;
mont(n-2);
multiply(a,ans);
cout<<a[1][5];
}
关于杨辉三角和组合数:
单个:
long long C(long long n,long long m){
int i,j;
a=1;
b=1;
if(m>n/2)m=n-m;
for(i=n,j=1;j<=m;i--,j++){
a*=i;
b*=j;
if(a%b==0){
a/=b;
b=1;
}
}
return a/b;
}
一排:组合数取模o(nlogn)
zuhe[0]=1;
zuhe[1]=t;
for(i=2;i<t;i++){
long long x,y,a,b;
long long niyuan=mont(i,mod-2,mod);
zuhe[i]=zuhe[i-1]*niyuan%mod*(t-i+1)%mod;
}
zuhe[t]=1;
还有一种,先预处理1--t的阶乘,直接弄,当然也要求逆元!o(nlongn)
线性筛质因数个数(重复的算多个):
for(i=2;i<=maxm;i++){
if(sum[i]==0){
prime[++tot]=i;
sum[i]=1;
}
for(j=1;j<=tot&&i*prime[j]<=maxm;j++){
sum[i*prime[j]]=sum[i]+1;
if((i%prime[j])==0)break;
}
线性筛莫比乌斯函数:
void pre(){
int i,j;
mobius[1]=1;
for(i=2;i<=50000;i++){
if(mark[i]==false){
prime[++tot]=i;
mobius[i]=-1;
}
for(j=1;j<=tot&&i*prime[j]<=50000;j++){
mark[i*prime[j]]=true;
if(i%prime[j]==0){
mobius[i*prime[j]]=0;
break;
}
mobius[i*prime[j]]=-mobius[i];
}
}
}