數論模板

本身雖然沒有好好看過數論的知識,,可是實際的作題中有一些處理老是須要數論的板子,,老是再作題的時候翻別人的博客抄很耽誤事,,並且對本身也很差,,因此總結一下日常用道的數論的板子,,git

求素數

埃篩

//判斷一個數是否爲質數
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;
}
相關文章
相關標籤/搜索