常用数学计算类函数(updating)

1.1组合数:从n个元素中取m个元素

原理:C(n,m)中分子可以用(n-m)*(n-m+1)*...*n表示,分母可以用1*2*...*m表示

ll C(ll n,ll m){
    ll ans = 1;
    for(ll i =1;i<=m;i++){
        ans = ans * (n-m+i)/i; // 注意一定要先乘再除
    }
    return ans;
}

1.2基于慢速乘和快速幂的组合数

原理:很简单,在组合数的基础上将循环体中的乘法和除法用慢速乘和快速幂表示

typedef unsigned long long ull;
ull sl(ull n, ull k, ull mod)
{
    ull ans = 0;
    while (k)
    {
        if (k & 1)ans = (ans + n) % mod;
        k >>= 1, n = (n + n) % mod;
    }
    return ans;
}
ull qp(ull a, ull k, ull p)
{
    ull res = 1;
    while (k)
    {
        if (k & 1)res = sl(res, a, p);
        k >>= 1; a = sl(a, a, p);
    }
    return res;
}
ull C(ull n, ull m,ull mod) 
{
    ull ans = 1;
    for (ull i = 1; i <= m; i++) {
        ans = (sl(ans, (n - m + i),mod)*qp(i,mod-2,mod))%mod;
    }
    return ans;
}

2.基于慢速乘的快速幂:

(1)慢速乘:n*k可以看作是k个n相加,通过二进制不断减去2^λ个n(^为幂运算,λ为从二进制第一位开始的位数),直到减到不满足while(k)为止。

原理:通过从基本的循环k次转化为μ个2^λ次方个n相加来减少计算次数.

(2)快速幂:n^k可以看作是k个n相乘,与慢速乘不同的是,快速幂是通过将k的二进制不断减去2^λ个k(^为幂运算,λ为从二进制第一位开始的位数),直到减到不满足while(k)为止。

原理:通过将基本的循环k次转化为μ个2^λ次方的n相乘来减少计算次数.

ull sl(ull n, ull k, ull mod)
{
	ull ans = 0;
	while (k)
	{
		if (k & 1)ans = (ans + n) % mod;
		k >>= 1, n = (n + n) % mod;
	}
	return ans;
}
ull qp(ull a, ull k, ull p)
{
	ull res = 1;
	while (k)
	{
		if (k & 1)res = sl(res, a, p);
		k >>= 1; a = sl(a, a, p);
	}
	return res;
}

那可能有聪明的小伙子要问了:"为啥不直接用快速幂的函数,还要结合慢速乘折磨自己多写几行呢?"

typedef long long ll;

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

问得好,但当遇到形如(a*b)^(c*d)次方时,单凭快速幂的能力就无法解决这样的问题了

res=res*a%p

这样的乘法我们就可以用慢速乘来解决.

3.博弈论之巴什博弈

问题:一共有n个物品,甲和乙最少可以取一次最多可以取m次,取完最后一个者获胜。

如果可以把n看成k*(m+1)+x的形式,只要甲取到x个,那么无论乙取多少个,甲都可以还原n为k*(m+1),当k=1时无论乙怎么取都取不完,此时甲即可获胜。

相反,如果n为k*(m+1),此时乙即为上情况的甲,此时乙即可获胜

4.埃筛

原理:筛掉若干个合数并把所剩余的质数给储存起来

这样说有一点抽象,直接上代码

const int N = 1e6 + 10;//先整他一个数集
bool st[N];//筛
int primes[N];//存
int cnt = 0;
void get_primes(int a)
{
	for (int i = 2; i < N; i++)
	{
		if (st[i])
		{
			continue;
		}
		primes[cnt++] = i;
		for (int j = i + i; j < N; j += i)//将该质数的倍数全筛掉
		{
			st[j] = true;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值