自己虽然没有好好看过数论的知识,,但是实际的做题中有一些处理总是需要数论的板子,,总是再做题的时候翻别人的博客抄很耽误事,,而且对自己也不好,,所以总结一下平常用道的数论的板子,,
求素数
埃筛
//判断一个数是否为质数
bool prime[maxn];
void init()
{
for(int i = 2; i < maxn; ++i)prime[i] = true;
for(int i = 2; i * i < maxn; ++i)
if(prime[i])
for(int j = i * i; j < maxn; j += i)
prime[j] = false;
}
线筛
bool prime[maxn];
int p[maxn], tot;
void init()
{
for(int i = 2; i < maxn; ++i)prime[i] = true;
for(int i = 2; i < maxn; ++i)
{
if(prime[i])p[tot++] = i;
for(int j = 0; j < tot && i * p[j] < maxn; ++i)
{
prime[i * p[j]] = false;
if(i % p[j] == 0)break;
}
}
}
筛质数的同时求质数的逆元,,(欧拉函数可能用)
//find all prime from 1 to maxn
bool isprime[maxn];
int prime[maxn], tot = -1;
int inv_prime[maxn];
void init() //寻找maxn以内的质数及其质数的逆元
{
for(int i = 2; i <= maxn; ++i)isprime[i] = false;
for(int i = 2; i <= maxn; ++i)
{
if(!isprime[i])prime[++tot] = i, inv_prime[tot] = pow_(i, mod - 2, mod);
for(int j = 0; j <= tot && i * prime[j] <= maxn; ++j)
{
isprime[i * prime[j]] = true;
if(i % prime[j] == 0)break;
}
}
}
预处理每个数的质因数
vector<int> prime_factor[maxn];
void init()
{
for(int i = 2; i < maxn; ++i)
if(prime_factor[i].size() == 0)
for(int j = i; j < maxn; j += i)
prime_factor[j].push_back(i);
}
预处理每个数的所有因数
vector<int> factor[maxn];
void init()
{
for(int i = 2; i <= maxn; ++i)
for(int j = i; j <= maxn; j += i)
factor[j].push_back(i);
}
预处理每个数的 质因数分解
//18 2 3 3
vector<int> prime_factor[maxn];
void init()
{
int tmp;
for(int i = 2; i <= maxn; ++i)
{
if(prime_factor[i].size() == 0)
{
for(int j = i; j <= maxn; j += i)
{
tmp = j;
while(tmp == tmp / i * i)//直接取模貌似很费时
{
prime_factor[j].push_back(i);
tmp /= i;
}
}
}
}
}
快速幂
inline ll pow_(ll a, ll b, ll p) //快速幂
{
ll ret = 1;
while(b)
{
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
求a在mod下的逆元
费马小定理法
inline ll pow_(ll a, ll b, ll p) //快速幂
{
ll ret = 1;
while(b)
{
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
//inv(a)=a^(mod-2)(mod) 费马小定理
ll inv(ll a, ll p)
{
return pow_(a, p - 2, p);
}
扩展欧几里得法
void ex_gcd(ll a, ll b, ll &x, ll &y, ll &d)
{
if(!b){d = a, x = 1, y = 0;}
else
{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
ll inv(ll a, ll p)
{
ll d, x, y;
ex_gcd(a, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
递归法
ll inv(ll a, ll p)//求t关于p的逆元,注意:t要小于p,最好传参前先把t%p一下
{
return a == 1 ? 1 : (p - p / a) * inv(p % a, p) % p;
}
位运算的快读
inline int read() //快读
{
int ans=0;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}