ACM模板

数论

1.康托展开

2.第一类斯特林数

S ( n , m ) S(n,m) S(n,m)记为将 n n n个元素划分为 m m m个圆排列的方案数

递推式: S ( n , m ) = S ( n − 1 , m − 1 ) + ( n − 1 ) ∗ S ( n − 1 , m ) S(n,m) = S(n-1,m-1) + (n - 1) * S(n-1,m) S(n,m)=S(n1,m1)+(n1)S(n1,m) $ ,$ n > m n > m n>m

边界: S ( n , 0 ) = 0 S(n,0) = 0 S(n,0)=0 S ( n , n ) = 1 S(n,n) = 1 S(n,n)=1

3.逆元线性求组合数
void make_inv()
{
	fac[0] = inv[0] = inv[1] = 1;
	for (int i = 2; i < N; ++i)
	{
		inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
	}
	for (int i = 1; i < N; ++i)
	{
		fac[i] = fac[i-1] * i % MOD;
		inv[i] = inv[i] * inv[i - 1] % MOD;
	}
}
int C(int n,int m)
{
	if (n < m) return 0;
	return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
4.埃氏素数筛法
const int MAX_N = 1e5 + 10;
int CNT, prime[MAX_N];
bool vis[MAX_N];
void make_prime() {
    CNT = 0;
    for(int i = 2; i < MAX_N; ++i) {
        if(!vis[i]) {
            prime[++CNT] = i;
            for(int j = 2; j * i < MAX_N; ++j)
                vis[i*j] = true;
        }
    }
}
5.欧拉线性筛
int prime[30000010], minprime[30000010], phi[30000010];
// 第i个质数,i的最小质因子,i的欧拉函数
int euler(int n)
{
	int c=0,i,j;
	phi[1]=1;
	for(i=2; i<=n; i++)
	{
		if(!minprime[i])prime[++c]=i,minprime[i]=i,phi[i]=i-1;
		for(j=1; j<=c&&i*prime[j]<=n; j++)
		{
			minprime[i*prime[j]]=prime[j];
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
	return c;		// 返回n范围内素数个数
}
Miller_Rabin 快速大素数测试

可以测试 2 63 2^{63} 263(甚至更高)以下的数是否为素数(但可能是伪素数)

#define ull unsigned long long
const int S = 4; // 测试次数,一般4~8次

ull mulit_mod(ull n, ull a, ull MOD) {
    a %= MOD, n %= MOD;
    ull ans = 0;
    for(; n; n >>= 1, a = (a + a) % MOD)
        if(n & 1) ans = (ans + a) % MOD;
    return ans;
}

ull pow_mod(ull n, ull a, ull MOD) {
    ull ans = 1;
    for(; n; n >>= 1, a = mulit_mod(a, a, MOD))
        if(n & 1) ans = mulit_mod(ans, a, MOD);
    return ans;
}

bool Miller_Rabin(ull n, ull a) {
    ull d = n-1, s = 0, t;
    while(!(d&1)) d >>= 1, ++s;
    t = pow_mod(d, a, n);
    if(t == 1 || t == -1) return true;
    for(int i = 0; i < s; ++i) {
        if(t == n-1) return true;
        t = mulit_mod(t, t, n);
    }
    return false;
}

bool is_prime(ull n) {
    if(n < 2) return false;
    if(n == 2) return true;
    if((n&1) == 0) return false;
    srand(time(NULL));
    for(int i = 0; i < S; ++i) {
        ull a = rand() % (n-1) + 1;
        if(a != 1 && n % a == 0) return false;
        if(!Miller_Rabin(n, a))
            return false;
    }
    return true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值