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

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和弓道

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

扫描二维码关注公众号,回复: 8990517 查看本文章
#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\n", 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

猜你喜欢

转载自www.cnblogs.com/cminus/p/12273108.html
今日推荐