ACM数学(待更新)

0X01 质数

质数判定

试除法 ACM数学板子_预处理

bool is_prime(long long x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )//i*i<=x可能会溢出
if (x % i == 0)return false;
return true;
}

试除法优化ACM数学板子_#include_02

bool is_prime(ll a)
{
if(a==1)return 0;
if(a==2||a==3)return 1;
if(a%6!=1&&a%6!=5)return 0;
for(int i=5;i<=a/i;i+=6)
if(a%i==0||a%(i+2)==0)return 0;
return 1;
}

质数筛选

线性筛ACM数学板子_预处理_03

int primes[N], cnt;     // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉,后面可以直接用来判是否为素数
//n只会被最小质因子筛掉
void get_primes(int n)
{
memset(st,0,sizeof st);
st[0]=st[1]=1;
for (int i = 2; i <= n; i ++ )//不要忘记等号
{
if (!st[i]) primes[++cnt] = i;
for (int j = 1; primes[j] <= n / i; j ++ )//不要忘记等号
{
st[primes[j] * i] = true;//合数一定有最小质因数,用最小质因数的倍数筛去合数
if (i % primes[j] == 0) break;//prime[j]一定是i最小质因子,也一定是prime[j]*i的最小质因子
}
}
}

质因数分解

试除法分解质因数ACM数学板子_预处理

void divide(int n)
{
for(int i=2;i<n/i;i++)//不要忘记等号
if(n%i==0)//i一定是质数
{
int s=0;
while(n%i==0)
{
n/=i;
s++;
}
printf("%d %d\n",i,s);
}
if(n>1)printf("%d %d\n",n,1);//处理唯一一个>sqrt(n)的
puts(" ");
}

线性筛预处理分解质因数 ACM数学板子_预处理_05

//Author fishingrod
//CSDN:https://blog.csdn.net/qq_39354847
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long

ll T,Q,n,m,k,p,ans,cnt,sum,tmp,num,last;
map<int,int>prime;
int pri[N],st[N];//st标记同时预处理除i对应最小质因子

inline void get_primes(int n)
{
memset(st,0,sizeof st);
st[0]=st[1]=1;
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
pri[++cnt]=i;
st[i]=i;
}
for (int j = 1; pri[j] <= n / i; j ++ )
{
st[pri[j] * i]=pri[j];
if (i % pri[j] == 0) break;
}
}
}
inline void divide(int x)
{
prime.clear();
while(x>1)
{
prime[st[x]]++;
x/=st[x];
}
}

signed main()
{
n=scanf("%d",&n);
get_primes(n);
for(int i=2; i<=n; i++)divide(i);
return 0;
}

0X02 约数

求约数集合

试除法求N的正约数集合ACM数学板子_预处理

vector<int>get_divisors(int n)
{
vector<int>res;
for(int i=1;i<=n/i;i++)//从1开始,约数啊
if(n%i==0)
{
res.push_back(i);
if(i!=n/i)res.push_back(n/i);//约数通常成对出现,特判完全平方
}
sort(res.begin(),res.end());
return res;
}

倍数法求1~N每个数的约数集合ACM数学板子_#include_07

约数个数

求多个数约数个数之和 ACM数学板子_预处理_08

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int mod=1e9+7;
int main()
{
int n;
cin>>n;
unordered_map<int,int>primes;
while(n--)
{
int x;
cin>>x;
for(int i=2;i<=x/i;i++)//可以用线性筛预处理优化
while(x%i==0)
{
x/=i;
primes[i]++;
}
if(x>1)primes[x]++;
}
LL res=1;
for(auto prime:primes)res=res*(prime.second+1)%mod;
cout<<res<<endl;
return 0;
}

求阶乘约数个数之和

#include<bits/stdc++.h>
using namespace std;

int main()
{
int res=0,n;
cin>>n;
for(int i=1;i<=n;i++)res+=n/i;
cout<<res;
return 0;
}

整除分块

ans = 0;
for(int l = 1, r; l <= n; l = r + 1)//知道左端点和分块数值求右端点
{
r = n / (n / l);
ans += n / l * (r - l + 1);
}

GCD/LCM ACM数学板子_i++_09

ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
ll lcm(ll a,ll b)
{
return a/gcd(a,b)*b;
}

互质与欧拉函数

欧拉函数

ll phi(ll x)
{
ll res = x;
for (int i = 2; i <= x / i; 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;
}

筛法求欧拉函数(1~n,欧拉函数之和)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e6+10;
ll primes[N],n,phi[N],cnt;
bool st[N];

ll get_eulers(ll n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;primes[j]<=n/i;j++)
{
st[i*primes[j]]=1;
if(i%primes[j]==0)
{
phi[i*primes[j]]=phi[i]*primes[j];
break;
}
phi[i*primes[j]]=phi[i]*(primes[j]-1);
}
}
ll res=0;
for(int i=1;i<=n;i++)res+=phi[i];
return res;
}

int main()
{
int n;
cin>>n;
cout<<get_eulers(n);

}

0X03 组合计数

求组合数并取模

递推ACM数学板子_i++_10

for (int i = 0; i < N; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;

逆元预处理ACM数学板子_#include_07

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, mod = 1e9 + 7;


int fact[N], infact[N];


int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}


int main()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}


int n;
scanf("%d", &n);
while (n -- )
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}

return 0;
}