ACM数学板子

ACM数学(待更新)

0X01 质数

质数判定

试除法 O ( N ) O(\sqrt N) O(N )
bool is_prime(long long x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )//i*i<=x可能会溢出
        if (x % i == 0)return false;
    return true;
}
试除法优化 O ( N / 3 ) O(\sqrt N/3) O(N /3)
bool is_prime(ll a)
{
    if(a==1)return 0;
    if(a==2||a==3)return 1;
    if(a%6!=1&&a%6!=5)return 0;
    for(int i=5;i<=a/i;i+=6)
        if(a%i==0||a%(i+2)==0)return 0;
    return 1;
}

质数筛选

线性筛 O ( N ) O(N) O(N)
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉,后面可以直接用来判是否为素数
//n只会被最小质因子筛掉
void get_primes(int n)
{
    memset(st,0,sizeof st);
    st[0]=st[1]=1;
    for (int i = 2; i <= n; i ++ )//不要忘记等号
    {
        if (!st[i]) primes[++cnt] = i;
        for (int j = 1; primes[j] <= n / i; j ++ )//不要忘记等号
        {
            st[primes[j] * i] = true;//合数一定有最小质因数,用最小质因数的倍数筛去合数
            if (i % primes[j] == 0) break;//prime[j]一定是i最小质因子,也一定是prime[j]*i的最小质因子
        }
    }
}

质因数分解

试除法分解质因数 O ( N ) O(\sqrt N) O(N )
void divide(int n)
{
	for(int i=2;i<n/i;i++)//不要忘记等号
		if(n%i==0)//i一定是质数 
		{
			int s=0;
			while(n%i==0)
			{
				n/=i;
				s++;
			}
			printf("%d %d\n",i,s);
		}
	if(n>1)printf("%d %d\n",n,1);//处理唯一一个>sqrt(n)的 
	puts(" ");
}
线性筛预处理分解质因数 O ( N 的 质 因 数 的 个 数 ) O(N的质因数的个数) O(N)
//Author fishingrod
//CSDN:https://blog.csdn.net/qq_39354847
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long

ll T,Q,n,m,k,p,ans,cnt,sum,tmp,num,last;
map<int,int>prime;
int pri[N],st[N];//st标记同时预处理除i对应最小质因子

inline void get_primes(int n)
{
	memset(st,0,sizeof st);
	st[0]=st[1]=1;
	for (int i = 2; i <= n; i ++ )
	{
		if (!st[i])
		{
			 pri[++cnt]=i;
			 st[i]=i;
		}
		for (int j = 1; pri[j] <= n / i; j ++ )
		{
			st[pri[j] * i]=pri[j];
			if (i % pri[j] == 0) break;
		}
	}
}
inline void divide(int x)
{
	prime.clear();
	while(x>1)
	{
		prime[st[x]]++;
		x/=st[x];
	}
}

signed main()
{
	n=scanf("%d",&n);
	get_primes(n);
	for(int i=2; i<=n; i++)divide(i);
	return 0;
}

0X02 约数

求约数集合

试除法求N的正约数集合 O ( N ) O(\sqrt N) O(N )
vector<int>get_divisors(int n)
{
	vector<int>res;
	for(int i=1;i<=n/i;i++)//从1开始,约数啊
		if(n%i==0)
		{
			res.push_back(i);
			if(i!=n/i)res.push_back(n/i);//约数通常成对出现,特判完全平方 
		}
	sort(res.begin(),res.end());
	return res;
}
倍数法求1~N每个数的约数集合 O ( N l o g N ) O(NlogN) O(NlogN)

约数个数

求多个数约数个数之和 O ( N N ) O(N\sqrt N) O(NN )
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int mod=1e9+7;
int main()
{
	int n;
	cin>>n;
	unordered_map<int,int>primes;
	while(n--)
	{
		int x;
		cin>>x;
		for(int i=2;i<=x/i;i++)//可以用线性筛预处理优化
			while(x%i==0)
			{
				x/=i;
				primes[i]++;
			}
		if(x>1)primes[x]++;
	}
	LL res=1;
	for(auto prime:primes)res=res*(prime.second+1)%mod;
	cout<<res<<endl;
	return 0;
}
求阶乘约数个数之和
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int res=0,n;
    cin>>n;
    for(int i=1;i<=n;i++)res+=n/i;
    cout<<res;
    return 0;
}

整除分块

ans = 0;
for(int l = 1, r; l <= n; l = r + 1)//知道左端点和分块数值求右端点
{
    r = n / (n / l);
    ans += n / l * (r - l + 1);
}

GCD/LCM O ( l o g ( a + b ) ) O(log(a+b)) O(log(a+b))

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}
ll lcm(ll a,ll b)
{
    return a/gcd(a,b)*b;
}

互质与欧拉函数

欧拉函数
ll phi(ll x)
{
    ll res = x;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) res = res / x * (x - 1);

    return res;
}
筛法求欧拉函数(1~n,欧拉函数之和)
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e6+10;
ll primes[N],n,phi[N],cnt;
bool st[N];

ll get_eulers(ll n)
{
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;primes[j]<=n/i;j++)
        {
            st[i*primes[j]]=1;
            if(i%primes[j]==0)
            {
                phi[i*primes[j]]=phi[i]*primes[j];
                break;
            }
            phi[i*primes[j]]=phi[i]*(primes[j]-1);
        }
    }
    ll res=0;
    for(int i=1;i<=n;i++)res+=phi[i];
    return res;
}

int main()
{
    int n;
    cin>>n;
    cout<<get_eulers(n);
    
}

0X03 组合计数

求组合数并取模

递推 O ( N 2 ) O(N^2) O(N2)
for (int i = 0; i < N; i ++ )
    for (int j = 0; j <= i; j ++ )
        if (!j) c[i][j] = 1;
        else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
逆元预处理 O ( N l o g N ) O(NlogN) O(NlogN)
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, mod = 1e9 + 7;


int fact[N], infact[N];


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


int main()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++ )
    {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }


    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }

    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值