算法数学定理总结中

约数个数定理:求解一个大于1的正约数的个数和。

     对于大于1的正数分解质数因数 :  n=\prod_{i=1}^{k}{_{p_{i}}}^{a_{i}}={_{p_{1}}}^{a_{1}}*{_{p_{2}}}^{a_{2}}*...*{_{p_{k}}}^{a_{k}}

     正约个数总和为:f(n)=\prod_{i=1}^{k}({a_{i}+1)=({a_{1}+1)*({a_{2}+1)*...*({a_{k}+1)

      详细介绍参考:百度百科

问题:求解正整数378000共有多少个正约数?

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7 + 10;
#define ll long long
int zhi[N], sum[N], cnt;
bool vis[N];
void get_zhi(int n) {   //线性求解质数
    for (int i = 2; i <= n; ++i) {
        if (!vis[i])zhi[cnt++] = i;
        for (int j = 2 * i; j <= n; j += i) {
            vis[j] = true;
        }
    }
}

int main()
{
    int n = 378000;
    get_zhi(n);
    for (int i = 0; i < cnt; ++i) {
        int p = zhi[i];
        int k = 0;
        while (n%p==0) {
            n /= p;
            k++;
        }
        sum[i] = k;
    }
    ll ans = 1;
    for (int i = 0; i < cnt; ++i) {
        ans *= (sum[i] + 1);
    }
    cout << ans;
    return 0;
}

其他公式待整理

欧几里得:

ax+by=c;

若a,b互为质数,则x,y一定有解且无穷多个。

x,y>=0,使得ax+by=c无解的c个数有限,

且 存在max(c|c导致方程无解)=a*b-a-b

欧几里得扩展定理:

 a mod b==a-a/b*b   其中(a/b向下取证)

洛谷--P1082 [NOIP2012 提高组] 同余方程

#include<bits/stdc++.h>

using namespace std;

#define ll long long

ll a, b, x, y;

//哦欧几里得扩展定理 可以求解逆元

ll exgcd(ll a, ll b, ll& x, ll& y) {

if (!b) {

x = 1;

y = 0;

return a;

}

ll d = exgcd(b, a % b, x, y);

ll t = x;

x = y;

y = t - (a / b) * y;

return d;

}

int main() {

cin >> a >> b;

ll g = exgcd(a, b, x, y);

cout << (x + b) % b;

return 0;

}

线性求逆元:

//洛谷--P3811 【模板】乘法逆元

//线性求逆元法

#include<bits/stdc++.h>

#define ll long long

using namespace std;

ll n, p, inv[3000005];

int main() {

scanf_s("%lld%lld", &n, &p);

inv[1] = 1;

printf("%lld\n", inv[1]);

for (ll i = 2; i <= n; ++i) {

inv[i] = (p - p / i) * inv[p % i] % p;

//技巧 其中p==m   -p/i%p==(p-p/i)%m==p%m-p/i%m==0-p/i%p  防止出现负数

printf("%lld\n", inv[i]);

}

return 0;

}

快速幂求逆元:

//洛谷--P2613 【模板】有理数取余

#include<bits/stdc++.h>

using namespace std;

#define ll long long

const ll mod = 19260817;

//快读

inline int read() {

int x = 0, f = 1;

char ch = getchar();

while (ch < '0' || ch>'9') {

if (ch == '-')f = -1;

ch = getchar();

}

while (ch >= '0' && ch <= '9') {

x = (x * 10 % mod + (ch - '0')) % mod; //  x*10==x<<1+x<<3

ch = getchar();

}

return x%mod*f;

}

//快速幂 log

ll qpow(ll a, ll b, ll m) {

a %= m;

ll res = 1;

while (b > 0) {

if (b & 1)res = res * a % m;

a = a * a % m;

b >>= 1;

}

return res;

}

ll a, b;

int main() {

a = read(), b = read();

if (b == 0)cout << "Angry!";

else cout << a * qpow(b, mod - 2, mod) % mod;

return 0;

}

卡特兰数(组合数学):

//洛谷--P1044 [NOIP2003 普及组] 栈

// 数学组合 卡特兰数 模板

#include<bits/stdc++.h>

#define ll long long

using namespace std;

ll n,f[25];

int main() {

cin >> n;

f[1] = 1;

for (ll i = 2; i <= n; ++i)

f[i] = f[i - 1] * (4 * i - 2) / (i + 1); 卡特兰数 模板

cout << f[n];

return 0;

}

//洛谷--P1375 小猫

//定义数学组合

#include<bits/stdc++.h>

#define ll long long

using namespace std;

const ll mod = 1e9 + 7;

const ll  MAX = 1000005;

ll n, f[MAX], inv[MAX];

ll qpow(ll a, ll b, ll m) {

a %= m;

ll res = 1;

while (b) {

if (b & 1)res = res * a % m;

a = a * a % m;

b >>= 1;

}

return res;

}

void pre() {

f[0] = 1;

for (int i = 1; i <= 1e6; ++i) {

f[i] = f[i - 1] * i % mod;

inv[i] = qpow(f[i], mod - 2, mod);

}

}

ll c(ll n, ll m) {

return f[n] * inv[m] % mod * inv[n - m] % mod;

//定义 n!/(m!*(n-m)!)

}

int main() {

pre();

cin >> n;

cout << c(2 * n, n) * qpow(n + 1, mod - 2, mod) % mod;

return 0;

}

错排:

//洛谷--P4071 [SDOI2016]排列计数

#include<bits/stdc++.h>

#define ll long long

using namespace std;

const ll mod = 1e9 + 7;

const ll MAX = 1e6 + 5;

ll t, n, m, f[MAX], d[MAX], inv[MAX];

ll qpow(ll a, ll b, ll m) {

a %= m;

ll res = 1;

while (b > 0) {

if (b & 1)res = res * a % m;

a = a * a % m;

b >>= 1;

}

return res;

}

void pre() {

f[0] = 1;

for (ll i=1; i <= 1e6; ++i) {

f[i] = f[i - 1] * i % mod;

inv[i] = qpow(f[i], mod - 2, mod);

}

inv[0] = inv[1];

d[1] = 0, d[2] = 1;

for (ll i = 3; i <= 1e6; ++i) { //错排

d[i] = (i - 1) * (d[i - 1] + d[i - 2]) % mod;

}

}

ll c(ll n, ll m) {

return f[n] * inv[m] % mod * inv[n - m] % mod;

}

int main() {

pre();

scanf_s("%lld", &t);

while (t--) {

scanf_s("%lld%lld", &n, &m);

if (n == m)printf("1\n");

else printf("%lld\n", c(n, m) * d[n - m] % mod);

}

return 0;

}

容斥原理:

洛谷--P1450 [HAOI2008] 硬币购物

 容斥原理

#include<bits/stdc++.h>

#define ll long long

using namespace std;

ll n, dp[100005], c[5], d[5], s,ans;

int main() {

cin >> c[1] >> c[2] >> c[3] >> c[4] >> n;

dp[0] = 1;

for (int i = 1; i <= 4; ++i) {

for (int j = c[i]; j <= 1e5; ++j) {

dp[j] += dp[j - c[i]];

}

}

while (n--) {

cin >> d[1] >> d[2] >> d[3] >> d[4] >> s;

    ans=0;

for (int i = 1; i < (1 << 4); ++i) {

ll f = -1, sum = 0;

for (int j = 1; j <= 4; ++j) {

if ((1 << (j - 1)) & i)

f *= -1, sum += c[j] * (d[j] + 1);

}

if (s >= sum)ans += f * dp[s - sum];

}

cout << dp[s]-ans << endl;

}

return 0;

}

全排列算法:无重复元素

/*递归回溯生产全排列,使用于无重复元素的情况*/

/*考虑第k位,前面已经排列*/

f[0];

void f(int k) {

    if (k == 9) {        //一种排列

        if (check())

            ans++;

    }

    //从k往后的每个数字都可以放在k位

    for (int i = k; i < 9; ++i) {

        {int t = a[k]; a[k] = a[i]; a[i] = t; }

        f(k + 1);

        {int t = a[k]; a[k] = a[i]; a[i] = t; }

    }

}

数组约分:  

法一:

long long C(int n, int m) { //n=6 m=2 

if(m < n-m) m = n-m; //n=6 m=4

long long ans = 1;

for(int i = m+1; i <= n; i++) ans *= i; // 5*6

for(int i = 1; i <= n-m; i++) ans /= i; // /1/2

return ans;       //15

}

法二

long long C(int n, int m) {

Long long res=1;

For(int i=a,j=1;j<=b;++j,--i){

Res*=res*i/j;

}

Return res;      

}

分割平面、空间问题 数学公式

(1) n条直线最多分平面问题

题目:n条直线,最多可以把平面分为多少个区域。

公式:f(n)=n(n+1)/2+1

(2)折线分平面

公式:f(n)=2n^2-n+1

(3)封闭曲线分平面

公式:f(n)=n^2-n+2

(4)平面分割空间问题

公式:f(n)=(n^3+5n)/6+1

两点式直线方程:

(y1-y2) * x +(x2-x1) * y +( x1 * y2 - x2 * y1)=0

并查集

/*蓝桥杯 蓝桥侦察 并查集 */

// https://www.lanqiao.cn/problems/1136/learning/

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int n, m, far[N << 1];

int find(int x) {

    if (x == far[x]) return x;

    return far[x] = find(far[x]);

}

void Union(int x, int y) {

    int tx = find(x), ty = find(y);

    if (tx != ty)far[tx] = ty;

}

int main() {

    int res = 0, pos = 0;

    cin >> n >> m;

    for (int i = 1; i <= 2 * n; ++i) far[i] = i;

    for (int i = 1; i <= m; ++i) {

        int x, y;

        cin >> x >> y;

        if (res) continue;

        {

            if (find(x) == find(y) || find(x + n) == find(y + n))

res = x, pos = i;

            Union(x, y + n), Union(x + n, y);

        }

    }

    cout << res << endl;;

    return 0;

}

/*

测试:

------------------

输入:

4 5

1 2

1 3

2 3

3 4

1 4

输出:

2

---------------------

*/

/*并查集*/

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;//数据太大 要开ll

const int N = 100010;

int p[N];

int find(int x) {

    if (p[x] != x) {

        p[x] = find(p[x]);

    }

    return p[x];

}

int main() {

    int n, m, x;

    cin >> n >> m >> x;

    for (int i = 1; i <= n; i++) {

        p[i] = i;

    }

    while (m--) {

        int a, b;

        cin >> a >> b;

        p[find(a)] = find(b);

    }

    while (x--) {

        int a, b;

        cin >> a >> b;

        if (find(a) == find(b)) {

            puts("Yes");

        }

        else {

            puts("No");

        }

    }

    return 0;

}

前N相求和的树状法

#include<bits/stdc++.h>

using namespace std;

int lowbit(int n) {

    return n - (n & (n - 1));

}

void update(int n, int i, int v, int f[]) {

    for (int k = i; k <= n; k += lowbit(k)) {

        f[k] += v;

    }

}

int getsum(int c[], int i) {

    int sum = 0;

    for (int k = i; k >= 1; k -= lowbit(k)) {

        sum += c[k];

    }

    return sum;

}

int main() {

    int arr[] = { 1,2,3,4,5,6,7,8,9 };

    int f[9];

    memset(f, 0, sizeof(f));

    for (int i = 0; i < 9; ++i) {

        update(9, i + 1, arr[i], f);

    }

    cout << getsum(f, 0) << endl; // 0

    cout << getsum(f, 1) << endl; // 1

    cout << getsum(f, 9) << endl; // 45

    return 0;

}

一位数组求和公式(动态规划、前缀和):

#include<bits/stdc++.h>

using namespace std;

int dp[100],s[100];

int main() {

int n;

cin >> n;

for (int i = 1; i <= n; ++i) {

cin >> s[i];

}

for (int i = 1; i <= n; ++i) {

dp[i] = dp[i - 1] + s[i];

}

int m;

cin >>m;

cout << dp[m] << endl; //局部求和公式

return 0;

}

/*

10

1 2 3 4 5 6 7 8 9 10

5

15

*/

二维数组求和公式(动态规划、前缀和):

#include<bits/stdc++.h>

using namespace std;

int dp[100][100], s[100][100];

int main() {

int n, m;

cin >> n >> m;

for (int i = 1; i <= n; ++i) {

for (int j = 1; j <= m; ++j) {

cin >> s[i][j];

}

}

for (int i = 1; i <= n; ++i) {

for (int j = 1; j <= m; ++j) {

dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + s[i][j]; //二维数组求和公式

}

}

int x1, x2, y1, y2;

cin >> x2 >> y2 >> x1 >> y1;

cout << dp[x2][y2] - dp[x2 - 1][y1 - 1] - dp[x1 - 1][y2] + s[x1 - 1][y1 - 1] << endl; //局部求和公式

return 0;

}

/*

3 4

1 2 3 4

5 6 7 8

9 10 11 12

2 2 0 0

14

*/

三角形面积公式:

三角形面积公式_百度百科

分解质因数

#include<bits/stdc++.h>

using namespace std;

int main() {

    int x;

    cin >> x;

    for (int i = 2; i <= x; ++i) {

        while (x != i) {

            if (x % i == 0) {

                cout << i << "*";

                x /= i;

            }

            else break;

        }

    }

    cout << x << endl;

    return 0;

}

/*

测试:

-------------

输入:

160

输出:

2*2*2*2*2*5

--------------

输入:

10

输出:

2*5

--------------

*/

裴蜀定理(或贝祖定理)

a,b互质充分必要条件是存在整数x,y使ax+by=1.

约定个数定理:https://baike.baidu.com/item/%E7%BA%A6%E6%95%B0%E4%B8%AA%E6%95%B0%E5%AE%9A%E7%90%86/4926961

1约数个数定理

对于一个大于1正整数n可以分解质因数

则n的正约数的个数就是。

其中a1、a2、a3…ak是p1、p2、p3,…pk的指数。

2定理简证

首先同上,n可以分解质因数:n=p1^a1×p2^a2×p3^a3*…*pk^ak,

由约数定义可知p1^a1的约数有:p1^0, p1^1, p1^2......p1^a1 ,共(a1+1)个;同理p2^a2的约数有(a2+1)个......pk^ak的约数有(ak+1)个。

故根据乘法原理:n的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1)。

3例题

例题:正整数378000共有多少个正约数?

解:将378000分解质因数378000=2^4×3^3×5^3×7^1

由约数个数定理可知378000共有正约数(4+1)×(3+1)×(3+1)×(1+1)=160个。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值