各种模板 - 持续更新中

Lucas定理求C(n,m)% P:

typedef long long LL;

LL mod;

inline LL pow(LL a, LL b)//快速幂是为了求逆元
{
    LL ans = 1;
    for(; b; b >>= 1,a = a * a % mod)
        if(b & 1)
            ans = ans * a % mod;
    return ans;
}

LL farc[1000005];

inline void prepare(LL a)
{
    farc[0]=1;
    for(LL i = 1; i <= a; ++i)
        farc[i]=farc[i-1]*i%mod;
}

inline LL Csmall(LL m, LL n) // C(m,n) = (n!)/(m!*(n-m)!)
{
    if(n < m)
        return 0;
    return farc[n] * pow(farc[m], mod-2) % mod * pow(farc[n-m], mod-2) % mod; // 费马小定理求逆元
}

inline LL C(LL m, LL n)
{
    if(n < m)
        return 0;
    if(!n)
        return 1;//Lucas的边界条件
    return C(m/mod, n/mod) % mod * Csmall(m%mod, n%mod) % mod; // 上面证明的Lucas定理
}

GCD:

LL gcd(LL a,LL b){
    while(b^=a^=b^=a%=b);
    return a;
}

Ex-GCD:

int Ex_Gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exGcd(b,a%b,x,y);
    t = x; x = y;
    y = t-a/b*y;
    return r;
}

Ex_GCD求逆元:

void extgcd(ll a,ll b,ll& d,ll& x,ll& y){
    if(!b){ d=a; x=1; y=0;}
    else{ extgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
ll inverse(ll a,ll n){
    ll d,x,y;
    extgcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}

快速幂:

ll pow_mod(ll x, ll n, ll mod){
    ll res=1;
    while(n>0){
        if(n&1)res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}

根据费马小定理,可用快速幂求逆元。

欧拉筛(线性):

bool IsPrime[10000001];
int Pri[2000001],PriN;
int FindPrime ( int MaxN ) {
    for( int i = 2 ; i <= MaxN ; ++i ){
        if( IsPrime[ i ] )
            Pri[ PriN++ ]=i; //将这句话放在下面的循环前以保证PriN和Pri值的完整性
        for(int j=0;j<PriN;++j){
            if( i*Pri[ j ] > MaxN )
                break; //当过大了就跳出
            IsPrime[ i * Pri[ j ] ] = 0;
            //筛去素数
            if( i % Pri[ j ] == 0 ) break;
            //这里是关键,如果i是一个合数(这当然是允许的)而且i mod prime[j] = 0
            //那么跳出,因为i*prime[ (- over -)j ]一定已经被筛去了,被一个素因子比i小的数
        }
    }
} 

大于等于5的质数一定和6的倍数相邻(适合访问量较小时):

bool isprime(ll n){
    if(n == 1)  return 0;
    if(n == 2 || n == 3)    return 1;
    if(n%6 != 5 && n%6 != 1)    return 0;
    for(ll i=5 ; i*i <= n; i += 6){
        if(n%i == 0 || n%(i+2) == 0)    return 0;
    }
    return 1;
}

KMP求两字符串是否匹配:

const int maxn = 2e6+100;
int n,m;
char s[maxn];
char t[maxn];
int next[maxn];
void getnext(){
    int i=0,j=-1;
    next[0] = -1;
    while(i<m){
        if(j == -1 || t[i] == t[j])
            next[++i] = ++j;
        else    j = next[j];
    }
    // for(int i=1;i<=m;++i)    printf("%d ", next[i]);
    // puts("");
}
bool kmp(){
    getnext();
    int i=0,j=0;
    while(i<n){
        if(j == -1 || s[i] == t[j]){
            i++;j++;
        }
        else j = next[j];
        if(j == m)    return 1;
    }
    return 0;
}

Manacher求最长回文字串:

const int N = 3e6;
char s[N];
char s_new[N];
int p[N];

int Init()
{
    int len = strlen(s);
    s_new[0] = '$';
    s_new[1] = '#';
    int j = 2;

    for (int i = 0; i < len; i++)
    {
        s_new[j++] = s[i];
        s_new[j++] = '#';
    }

    s_new[j] = '\0';  // 别忘了哦

    return j;  // 返回 s_new 的长度
}

int Manacher()
{
    int len = Init();  // 取得新字符串长度并完成向 s_new 的转换
    int max_len = -1;  // 最长回文长度

    int id;
    int mx = 0;

    for (int i = 1; i < len; i++)
    {
        if (i < mx)
            p[i] = min(p[2 * id - i], mx - i);  // 需搞清楚上面那张图含义, mx 和 2*id-i 的含义
        else
            p[i] = 1;

        while (s_new[i - p[i]] == s_new[i + p[i]])  // 不需边界判断,因为左有'$',右有'\0'
            p[i]++;

        // 我们每走一步 i,都要和 mx 比较,我们希望 mx 尽可能的远,这样才能更有机会执行 if (i < mx)这句代码,从而提高效率
        if (mx < i + p[i])
        {
            id = i;
            mx = i + p[i];
        }

        max_len = max(max_len, p[i] - 1);
    }

    return max_len;
}

猜你喜欢

转载自blog.csdn.net/qq_41009682/article/details/82112317