数学练习记

 

由于这个人觉得自己数学太差,他决定把紫书和蓝书的数学部分先刷一刷,再买本具体数学啃一啃,再把组合数学啃一啃,再把 PE 刷一刷。

这个人觉得上面紫书两个字之后的那些话可以不用信了

【UVA11582】斐波那契数列取模找循环节问题,考虑数列中两个相邻元素什么时候和 $f[0]$ 与 $f[1]$ 一样,就是 $0$ 后面什么时候重新跟一个 $1$,最坏情况就是 $0$ 后面跟一个 $2$,走了一段长度为 $n$ 的序列,后面跟了一个 $3$ 再走了一段长度为 $n$ 的序列...所以最多 $n^2$ 长度会出现循环,求出周期后再对 $a^b$ 进行快速幂即可。

#include <bits/stdc++.h>
#define ull unsigned long long

int qp(int a, ull b, int MOD) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans % MOD;
}

const int N = 1e6 + 7;
int f[N];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        ull a, b;
        int n;
        scanf("%llu%llu%d", &a, &b, &n);
        f[0] = 0; f[1] = 1 % n;
        int t = 0;
        for (int i = 2; ; i++) {
            f[i] = (f[i - 1] + f[i - 2]) % n;
            if (f[i] == f[1] && f[i - 1] == f[0]) {
                t = i - 1;
                break;
            }
        }
        int aa = a % t;
        printf("%d\n", f[qp(aa, b, t)]);
    }
    return 0;
}
View Code

【UVA12169】可以得到 $x_3 = a^2 x_{1} + (a + 1)b \pmod {10001}$,数列长度只有 $200$(刚开始以为是 $10000$。。。),那么可以枚举 $a$,用扩展欧几里得得到 $b$,然后在 $O(T)$ 的时间check一下这个数列是否符合条件,然后就做完了。

#include <bits/stdc++.h>
#define ll long long

const int MOD = 10001;
const int N = 220;
ll f[N], in[N];

void exgcd(ll a, ll b, ll &d, ll &x, ll &y) {
    if (!b) { d = a, x = 1, y = 0; }
    else { exgcd(b, a % b, d, y, x); y -= x * (a / b); }
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= 2 * n; i += 2) 
        scanf("%lld", in + i);
    f[1] = in[1];
    for (int a = 0; a <= 10000; a++) {
        ll c = in[3] - a * a * in[1];
        ll d, b, z;
        exgcd(a + 1, 10001, d, b, z);
        if (c % d) continue;
        b *= c / d;
        bool flag = 1;
        for (int i = 2; i <= 2 * n; i++) {
            f[i] = f[i - 1] * a + b;
            f[i] %= MOD;
            if (i & 1) {
                if (f[i] != in[i]) {
                    flag = 0;
                    break;
                }
            }
        }
        if (!flag) continue;
        for (int i = 2; i <= 2 * n; i += 2)
            printf("%lld\n", f[i]);
        break;
    }
}
View Code

【UVA10375】求组合数,就是对分子分母都写成质数的形式,然后记录一下指数即可。

#include <bits/stdc++.h>

const int N = 10007;
int prime[N], zhi[N];
bool vis[N];

void init() {
    for (int i = 2; i < N; i++) {
        if (!vis[i]) prime[++prime[0]] = i;
        for (int j = 1; j <= prime[0] && i * prime[j] < N; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

void add(int n, int i, int v) {
    int p = prime[i];
    while (p <= n) {
        zhi[i] += v * n / p;
        if (n < 1LL * p * prime[i]) break;
        p *= prime[i];
    }
}

void add(int n, int v) {
    for (int i = 1; i <= prime[0]; i++) 
        add(n, i, v);
}

int main() {
    init();
    int p, q, r, s;
    while (~scanf("%d%d%d%d", &p, &q, &r, &s)) {
        for (int i = 1; i <= prime[0]; i++)
            zhi[i] = 0;
        add(p, 1);
        add(q, -1);
        add(p - q, -1);
        add(r, -1);
        add(s, 1);
        add(r - s, 1);
        double ans = 1;
        for (int i = 1; i <= prime[0]; i++)
            ans *= pow(prime[i], zhi[i]);
        printf("%.5f\n", ans);
    }
    return 0;
}
View Code

【UVA10791】把数唯一分解之后,然后每个数都单独取出来加上就行,只有一种质因子时加上1。

#include <bits/stdc++.h>

const int N = 22;
int p[N];

int main() {
    int n;
    int kase = 0;
    while (~scanf("%d", &n), n) {
        printf("Case %d: ", ++kase);
        if (n == 1) {
            puts("2");
            continue;
        }
        int k = sqrt(n + 0.5);
        p[0] = 0;
        for (int i = 2; 1LL * i * i <= n; i++) {
            if (n % i == 0) {
                p[++p[0]] = 1;
                while (n % i == 0)
                    p[p[0]] *= i, n /= i;
            }
        }
        if (n != 1) p[++p[0]] = n;
        if (p[0] == 1) {
            printf("%lld\n", 1LL * p[1] + 1LL);
        } else {
            int ans = 0;
            for (int i = 1; i <= p[0]; i++)
                ans += p[i];
            printf("%d\n", ans);
        }
    }
    return 0;
}
View Code

【UVA12716】设 $c = a - b$,因为 $gcd(a, b) \leq c \leq a$ xor $b$,那么当 $gcd(a, b) = a$ xor $b$ 时,$gcd(a, b) = a$ xor $b = c$,枚举 $a$、$c$,预处理一个 $sum[i]$ 表示 $i$ 为较大数时有多少较小数符合。做一下前缀和即可。复杂度 $O(nlogn)$。

#include <bits/stdc++.h>

const int N = 3e7 + 7;
int sum[N];

int main() {
    for (int i = 1; i < N; i++)
        for (int j = i + i; j < N; j += i)
            if ((j ^ (j - i)) == i)
                sum[j]++;
    for (int i = 1; i < N; i++)
        sum[i] += sum[i - 1];
    int T;
    scanf("%d", &T);
    for (int kase = 1; kase <= T; kase++) {
        int n;
        scanf("%d", &n);
        printf("Case %d: %d\n", kase, sum[n]);
    }
    return 0;
}
View Code

 【UVA1635】可以发现,就是一个杨辉三角,第 $i$ 的系数为 $C_{n-1}^{i-1}$,由定义可得递推式 $C_{n}^{i} = \dfrac{n - i + 1}{i} C_{n}^{i - 1}$,把递推式改成质因子次数的递推即可。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

int n, m;
const int M = 32000;
int prime[M];
bool vis[M];

void init() {
    for (int i = 2; i < M; i++) {
        if (!vis[i]) prime[++prime[0]] = i;
        for (int j = 1; j <= prime[0] && i * prime[j] < M; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

const int N = 1e5 + 7;
int who[20], zhi[20], cnt;
int ans[N][20];

void get(int n) {
    memset(who, 0, sizeof who);
    memset(zhi, 0, sizeof zhi);
    cnt = 0;
    for (int i = 1; i <= prime[0] && prime[i] <= n; i++) {
        if (n % prime[i]) continue;
        who[++cnt] = prime[i];
        while (n % prime[i] == 0)
            n /= prime[i], zhi[cnt]++;
        if (n == 1) break;
    }
    if (n != 1) {
        who[++cnt] = n;
        zhi[cnt]++;
    }
}

int main() {
    init();
    while (~scanf("%d%d", &n, &m)) {
        get(m);
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= cnt; j++)
                ans[i][j] = ans[i - 1][j];
            int x = n - i;
            for (int j = 1; j <= cnt; j++) {
                while (x % who[j] == 0)
                    ans[i][j]++, x /= who[j];
            }
            x = i;
            for (int j = 1; j <= cnt; j++) {
                while (x % who[j] == 0)
                    ans[i][j]--, x /= who[j];
            }
        }
        std::vector<int> res;
        for (int i = 0; i < n; i++) {
            bool flag = 1;
            for (int j = 1; j <= cnt; j++) 
                flag &= (ans[i][j] >= zhi[j]);
            if (flag) res.push_back(i + 1);
        }
        std::sort(res.begin(), res.end());
        printf("%d\n", (int)res.size());
        if (res.size()) {
            printf("%d", res[0]);
            for (int i = 1; i < res.size(); i++)
                printf(" %d", res[i]);
        }
        puts("");
    }
    return 0;
}
View Code

 【UVA10820】欧拉函数前缀和。

#include <bits/stdc++.h>

const int N = 50007;
int p[N], tol, phi[N];
bool vis[N];

void init() {
    for (int i = 2; i < N; i++) {
        if (!vis[i]) { 
            p[++tol] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= tol && i * p[j] < N; j++) {
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) {
                phi[i * p[j]] = phi[i] * p[j];
                break;
            }
            phi[i * p[j]] = phi[i] * phi[p[j]];
        }
    }
    for (int i = 2; i < N; i++)
        phi[i] += phi[i - 1];
}

int main() {
    int n;
    init();
    while (~scanf("%d", &n), n)
        printf("%d\n", phi[n] * 2 + 1);
    return 0;
}
View Code

 【UVA1262】对每一列求出能选的字母,那么总方案数就是每一列能选的字母数的乘积,然后判断 $k$ 是后继方案数的多少倍,那么每一列要选的字母就出来了。

#include <bits/stdc++.h>
#define select sel

const int N = 10;
char s[2][N][N];
bool vis[2][N][26];
int select[N][N];
char str[N];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int k;
        scanf("%d", &k);
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 6; j++)
                scanf("%s", s[i][j]);
        memset(vis, 0, sizeof(vis));
        memset(select, 0, sizeof(select));
        memset(str, 0, sizeof str);
        for (int j = 0; j < 5; j++) {
            for (int z = 0; z < 2; z++)
                for (int i = 0; i < 6; i++)
                    vis[z][j][s[z][i][j] - 'A'] = 1;
            for (int i = 0; i < 26; i++)
                if (vis[0][j][i] && vis[1][j][i])
                    select[j][++select[j][0]] = i;
            // for (int i = 1; i <= select[j][0]; i++)
            //     printf("%d ", select[j][i]);
            // puts("");
        }
        int ans = 1;
        for (int i = 0; i < 5; i++)
            ans *= select[i][0];
        if (k > ans) {
            puts("NO");
            continue;
        }
        k--;
        for (int i = 0; i < 5; i++) {
            ans /= select[i][0];
            int pos = k / ans;
            str[i] = (char)(select[i][pos + 1] + 'A');
            k %= ans;
        }
        str[5] = 0;
        puts(str);
    }
    return 0;
}
View Code

 

posted @ 2019-11-15 13:58  Mrzdtz220  阅读(151)  评论(0编辑  收藏  举报