• 2020牛客寒假算法基础集训营一 题解


    2都结束了我才补完1的题

    我真的太菜了


    总体来说不是很难(反正我也AK不了)

    A.honoka和格点三角形

    公式挺好推的,容斥随便搞搞就出来了,但是我错了8次....刚开始以为是取模的问题,后来把所有的数都取模了还是有问题,才发现因为用同余定理时候存在减法,会产生有负数的情况,所以需要(ans+MOD) % MOD,就这个简单的问题坑了我将近一个小时

    #include <cstdio>
    using namespace std;
    const long long MOD = 1e9 + 7;
    int main() {
        long long n, m;
        scanf("%lld %lld", &n, &m);
        n--; m--;
        long long ans = 0;
        n = n % MOD; m = m % MOD;
        ans = ((((((n - 1) % MOD * ((n + 1) % MOD)) % MOD) * (m % MOD)) % MOD) * 2) % MOD;
        ans = ans % MOD + (((((m + 1) % MOD * ((m - 1) % MOD)) % MOD) * (n % MOD)) % MOD * 2) % MOD;
        ans = ans % MOD + ((((((n + 1) % MOD * ((m - 1) % MOD)) % MOD) * (n % MOD)) % MOD) * 2) % MOD;
        ans = ans % MOD + ((((((n - 1) % MOD * ((m + 1) % MOD)) % MOD) * (m % MOD)) % MOD) * 2) % MOD;
        ans = ans % MOD - (((((n - 1) % MOD * (m % MOD)) % MOD) * 4) % MOD + ((((m - 1) % MOD * (n % MOD)) % MOD) * 4) % MOD) % MOD;
        ans = (ans + MOD) % MOD;
        printf("%lld", ans);
        return 0;
    }

    B.kotori和bangdream

    大水题

    #include <cstdio>
    using namespace std;
    int main() {
        int n, x, a, b;
        scanf("%d %d %d %d", &n, &x, &a, &b);
        double ans = (1.0 * x / 100) * a + (1 - 1.0 * x / 100) * b;
        ans *= n;
        printf("%.2lf", ans);
        return 0;
    }

    B.umi和弓道

    简单的计算几何,注意细节就行了,不过场上看到是计算几何直接吓跑了

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 100010;
    long double posy[N], posx[N];
    int main() {
        ll x0, y0;
        scanf("%lld %lld", &x0, &y0);
        int n, k, cx = 0, cy = 0;
        scanf("%d %d", &n, &k);
        for (int i = 0; i < n; i++) {
            ll x, y;
            scanf("%lld %lld", &x, &y);
            if (x * x0 > 0 && y * y0 > 0)
                continue;
            if (x * x0 < 0) {
                long double k = 1.0 * (y0 - y) / (x0 - x);
                posy[cy++] = y0 - k * x0;
            }
            if (y * y0 < 0) {
                if (x0 == x)
                    posx[cx++] = x0;
                else {
                    long double k = 1.0 * (y0 - y) / (x0 - x);
                    posx[cx++] = x0 - y0 * 1.0 / k;
                }
            }
        }
        sort(posx, posx + cx);
        sort(posy, posy + cy);
        long double ans = 5 * 1e9;
        for (int i = n - k - 1; i < cx; i++)
            ans = min(ans, posx[i] - posx[i - (n - k - 1)]);
        for (int i = n - k - 1; i < cy; i++)
            ans = min(ans, posy[i] - posy[i - (n - k - 1)]);
        if (ans == 5 * 1e9)
            puts("-1");
        else
            printf("%Lf", ans);
        return 0;
    }
    // y - y0 = k * (x - x0)
    // -y0/k = x - x0

    D.hanayo和米饭

    大水题*2(虽然我没加llWA了一发)

    #include <cstdio>
    using namespace std;
    int main() {
        long long n;
        scanf("%lld", &n);
        long long tot = (1 + n) * n / 2;
        for (int i = 0; i < n - 1; i++) {
            long long a;
            scanf("%lld", &a);
            tot -= a;
        }
        printf("%lld", tot);
        return 0;
    }

    E.rin和快速迭代


    刚开始超时了,还以为是太暴力了,结果测了大数据发现是因为int暴了,因为(int i = 0; i * i < n; i++)的时候,i * i还是一个int,就爆炸了,这个问题挺常见的,结果我还是没吸取教训QAQ

    #include <cstdio>
    using namespace std;
    typedef long long ll;
    int main() {
        ll n, ans = 0;
        scanf("%lld", &n);
        while (n != 2) {
            ll tot = 0;
            for (ll i = 1; i * i <= n; i++)
                if (n % i == 0) {
                    if (i * i == n)
                        tot++;
                    else
                        tot += 2;
                }
     
            n = tot;
            ans++;
        }
        printf("%lld", ans);
        return 0;
    }

    F.maki和tree


    赛后补的题,不同于标答的dfs,我就直接并查集合并,结果刚开始把黑色也合并了...错的很惨,后来改了发现超时,改成了路径压缩就过了

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int N = 100010;
    vector < int > e[N];
    int fa[N];
    int bl[N], cnt = 0;
    long long tot[N];
    int cl[N];
    int find(int a) {
        return (fa[a] == a) ? fa[a] : (fa[a] = find(fa[a]));
    }
    int main() {
        int n;
        scanf("%d", &n);
        getchar();
        for (int i = 1; i <= n; i++) {
            char c = getchar();
            if (c == 'W')
                cl[i] = 0;
            else {
                cl[i] = 1;
                bl[cnt++] = i;
            }
        }
        for (int i = 1; i <= n; i++)
            fa[i] = i, tot[i] = 1;
        for (int i = 0; i < n - 1; i++) {
            int a, b;
            scanf("%d %d", &a, &b);
            int f = find(a);
            int fb = find(b);
            if (f != fb && cl[a] == cl[b] && cl[a] == 0) {
                fa[fb] = f;
                tot[f] += tot[fb];
            }
            else if (f != fb && cl[a] != cl[b]) {
                e[f].push_back(fb);
                e[fb].push_back(f);
            }
        }
        long long ans = 0;
        for (int k = 0; k < cnt; k++) {
            int i = bl[k];
            tot[i] = 0;
            long long res = 0;
            for (int j = 0; j < e[i].size(); j++) {
                int q = find(e[i][j]);
                tot[i] += tot[q];
            }
            for (int j = 0; j < e[i].size(); j++) {
                int q = find(e[i][j]);
                res = res + (tot[i] - tot[q]) * tot[q];
            }
            res = res / 2;
            ans = ans + res + tot[i];
        }
        printf("%lld", ans);
        return 0;
    }
    //

    G.eli和字符串


    尺取法水题

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 200010;
    char s[N];
    int main() {
        int n, k;
        scanf("%d %d", &n, &k);
        scanf("%s", s);
        int ans = 0x3f3f3f3f;
        for (int i = 0; i < 26; i++) {
            int l = 0, r = 0, tot = 0;
            while (r < n) {
                if (tot < k) {
                    while (s[r] != i + 'a' && r < n) //注意这里的判断,不要越界了
                        r++;
                    if (s[r] == i + 'a') // 注意判断是哪种情况
                        tot++, r++;
                    else
                        break;
                }
                if (tot == k) {
                    while (s[l] != i + 'a' && l <= r)
                        l++;
                    ans = min(ans, (r - l));
                    tot--; l++;
                }
            }
        }
        if (ans == 0x3f3f3f3f)
            puts("-1");
        else
            printf("%d", ans);
        return 0;
    }

    H.nozomi和字符串

    尺取法水题*2

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 200010;
    char s[N];
    int main() {
        int n, k;
        scanf("%d %d", &n, &k);
        scanf("%s", s);
        int kk = k;
        int l = 0, r = 0, ans = 0;
        while (r < n) {
            if (k > 0){
                while (s[r] == '0' && r < n)
                    r++;
                ans = max(ans, r - l);
                if (s[r] == '1')
                    k--, r++;
                else
                    break;
            }
            if (k == 0) {
                while (s[r] == '0' && r < n)
                    r++;
                ans = max(ans, r - l);
                while (s[l] == '0' && l <= r)
                    l++;
                l++; k++;
            }
        }
        l = 0, r = 0;
        k = kk;
        while (r < n) {
            if (k > 0){
                while (s[r] == '1' && r < n)
                    r++;
                ans = max(ans, r - l);
                if (s[r] == '0')
                    k--, r++;
                else
                    break;
            }
            if (k == 0) {
                while (s[r] == '1' && r < n)
                    r++;
                ans = max(ans, r - l);
                while (s[l] == '1' && l <= r)
                    l++;
                l++; k++;
            }
        }
        printf("%d", ans);
        return 0;
    }

    I.nico和niconiconi

     线性dp,暴力一点就行了

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 3000010;
    char s[N];
    char s1[10] = "nico";
    char s2[10] = "niconi";
    char s3[11] = "niconiconi";
    long long dp[N];
    int main() {
        int n, a, b, c;
        scanf("%d %d %d %d", &n, &a, &b, &c);
        scanf("%s", s);
        for (int i = 3; i < n; i++) {
            dp[i + 1] = dp[i];
            for (int j = 0; j < 4; j++) {
                if (s[i - j] != s1[3 - j])
                    break;
                if (j == 3)
                    dp[i + 1] = max(dp[i + 1], dp[i - 4 + 1] + a);
            }
            if (i >= 5)
                for (int j = 0; j < 6; j++) {
                    if (s[i - j] != s2[5 - j])
                        break;
                    if (j == 5)
                        dp[i + 1] = max(dp[i + 1], dp[i - 6 + 1] + b);
                }
            if (i >= 9)
                for (int j = 0; j < 10; j++) {
                    if (s[i - j] != s3[9 - j])
                        break;
                    if (j == 9)
                        dp[i + 1] = max(dp[i + 1], dp[i - 10 + 1] + c);
                }
        }
        printf("%lld", dp[n]);
        return 0;
    }

    J .u's的影响力

     场上最难的题?斐波那契数列可以矩阵快速幂求,麻烦在取模上,幂太大了怎么办,反正我场上没想出办法,赛后看了题解发现可以用费马小定理%(mod - 1)解决,看了一个证明,看的有点懵(反正我也不负责数学)不过过段时间还是再看一遍吧,然后就是有很多坑

    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const ll MOD = 1e9 + 7;
    struct Matrix{
        ll m[3][3];
    };
     
    inline void assign(Matrix* a) {
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                a->m[i][j] = 0;
    }
    inline Matrix multi(Matrix a, Matrix b) {
        Matrix c;
        assign(&c); //初始化
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                for (int k = 0; k < 2; k++)
                    c.m[i][j] = ((a.m[i][k] * b.m[k][j] % (MOD - 1)) + c.m[i][j]) % (MOD - 1);
        return c;
    }
     
    ll pow1(ll n) {
        n--;
        Matrix res, a;
        assign(&res); assign(&a); //初始化
        res.m[0][0] = 1; res.m[1][1] = 1;
        a.m[0][0] = 1; a.m[0][1] = 1; a.m[1][0] = 1;
        while (n) {
            if (n & 1)
                res = multi(a, res);
            a = multi(a, a);
            n >>= 1;
        }
        return res.m[0][0];
    }
    ll pow2(ll a, ll b) {
        if (a % MOD == 0)   return 0; //快速幂一定要注意这个啊
        ll res = 1;
        a = a % MOD;       
        while (b) {
            if (b & 1)
                res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res % MOD;
    }
    int main() {
        ll n, x, y, a, b;
        scanf("%lld %lld %lld %lld %lld", &n, &x, &y, &a, &b);
        if (n == 1) {
            printf("%lld", x % MOD);
            return 0;
        }
        if (n == 2) {
            printf("%lld", y % MOD);
            return 0;
        }
        x %= MOD; y %= MOD;
        ll a1 = pow1(n - 2);
        ll b1 = pow1(n - 1);
        //printf("%lld %lld
    ", a1, b1);
        ll ans = pow2(x % MOD, a1) * pow2(y % MOD, b1) % MOD * pow2(a % MOD, (a1 + b1 - 1) * (b % (MOD - 1)) % (MOD - 1)) % MOD; // 取模真的要多来几次,不然就会爆炸
        printf("%lld", ans % MOD);
        return 0;
    }
    // f(1) = x, f(2) = y, f(3) = x * y * a^b, f(4) = x * y^2 * a^2b, f(5) = x^2 * y^3 * a^4b
    // f(6) = x^3 * y^5 * a^7b f(7) = x^5 * y^8 * a^12b f(8) = x^8 * y^13 * a^20b
  • 相关阅读:
    Python 模拟SQL对文件进行增删改查
    Python用户登陆
    计算程序的内存和占比
    列出top中的pid
    编写类du命令Python脚本
    生成器版本的文件MD5校验
    利用os、hash模块生成目录下所有文件的md5
    文件Copy和文件夹Copy
    Access数据库连接方式
    js常用方法收集
  • 原文地址:https://www.cnblogs.com/cminus/p/12273108.html
Copyright © 2020-2023  润新知