2021蓝桥杯省赛B组

A.空间

思路:八位 = 1B

256MB = 1024 * 1024 * 256 / 4 = 67108864

#include <bits/stdc++.h>
using namespace std;

int main() {
    cout << 1024 * 1024 * 256 / 4 << endl;
    return 0;
}

B.卡片

思路:暴力枚举 + 模拟

我的答案:3181

#include <bits/stdc++.h>
using namespace std;
int cnt[10];
int main() {
    for (int i = 0; i <= 9; ++ i) cnt[i] = 2021;
    int base = 1;
    while (1) {
        int tbase = base;
        while (tbase) {
            cnt[tbase % 10] --;
            if (cnt[tbase % 10] < 0) {
                cout << base - 1 << endl;
                return 0;
            }
            tbase /= 10;
        }
        base ++;

    }
    return 0;
}

C.直线 (这题摆烂了,考场上脑抽认为斜率相同就是相同的直线

思路:暴力枚举 + 模拟

这里给出赛后想的代码

我的答案:41255

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const double inf = 1e16;
struct Point {
    double x, y;
};

vector<Point> p;
set<pair<double, double> > ans;

int main() {
    for (int i = 0; i <= 19; ++ i) {
        for (int j = 0; j <= 20; ++ j) {
            p.push_back({i, j});
        }
    }
    for (int i = 0; i < p.size(); ++ i) {
        for (int j = i+1; j < p.size(); ++ j) {
            if (p[i].x - p[j].x == 0) {
                ans.insert({inf, p[i].x});
            }
            else {
                double k = (p[i].y - p[j].y) / (p[i].x - p[j].x);
                double b = p[i].y - k * p[i].x;
                ans.insert({k, b});
            }
        }
    }
    cout << ans.size() << endl;
    return 0;
}

但是上面的代码有点问题的因为set无法考虑的精度问题,所以需要用双重循环+上eps来判断

下面才是正解:

答案:40257

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const double eps = 1e-7;
const double inf = 1e16;

struct Point {
    double x, y;
};

vector<Point> p;
vector<pair<double, double> > ans;
vector<pair<double, double> > rec;
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x < eps) return -1;
    return 1;
}
int main() {
    for (int i = 0; i <= 19; ++ i) {
        for (int j = 0; j <= 20; ++ j) {
            p.push_back({i, j});
        }
    }
    for (int i = 0; i < p.size(); ++ i) {
        for (int j = i+1; j < p.size(); ++ j) {
            if (p[i].x - p[j].x == 0) {
                ans.push_back({inf, p[i].x});
            }
            else {
                double k = (p[i].y - p[j].y) / (p[i].x - p[j].x);
                double b = p[i].y - k * p[i].x;
                ans.push_back({k, b});
            }
        }
    }
    cout << ans.size() << endl;
    for (int i = 0; i < ans.size(); ++ i) {
            int flag = 0;
        for (int j = i+1; j < ans.size() && !flag; ++ j) {
            if (sgn(ans[i].first - ans[j].first) == 0 && sgn(ans[i].second - ans[j].second) == 0) flag = 1;
        }
        if (!flag) rec.push_back(ans[i]);

    }
    cout << rec.size() << endl;
    return 0;
}

D. 货物摆放

思路:将这个数的因数存入,之后枚举每个因数作为三元组的第一个部分,之后根据 n / 枚举的因数进行拆分枚举

我的答案:2430

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn = 2e6 + 10;
set<ll> two;

int main() {
    ll n = 2021041820210418;
    for (ll i = 1; i * i <= n; ++ i) {
        if (n % i == 0) {
            two.insert(i);
            two.insert(n/i);
        }
    }
    ll ans = 0;
    for (auto i : two) {
        ll temp = n / i; ///枚举每个因数作为三元组的第一个数
        ///之后从另一半里分解出两个数作为后面两个数
        for (ll j = 1; j * j <= temp; ++ j) {
            if (temp % j == 0) {
                ans += 2;
                if (temp == j*j) ans --;
                cout << i << "*" << j << "*" << temp/j << " = " << j*temp/j*i << endl;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

E.路径

思路:这道题没啥好说的。就是普通的建图跑最短路即可

我的答案:10266837

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
struct Edge {
    int v, nxt, w;
} E[maxn];
int head[20000], dis[20000];
int tot;
void add(int u, int v, int w) {
    E[++tot] = {v, head[u], w}, head[u] = tot;
}
int dij() {
    for (int i = 1; i <= 2021; ++ i) {
        dis[i] = inf;
    }
    priority_queue<pii, vector<pii>, greater<pii> > pq;
    pq.push({dis[1] = 0, 1});
    while (pq.size()) {
        int u = pq.top().second;
        pq.pop();
        for (int i = head[u]; i; i = E[i].nxt) {
            int w = E[i].w;
            int v = E[i].v;
            if (dis[u] + w < dis[v]) {
                pq.push({dis[v] = dis[u] + w, v});
            }
        }
    }
//    for (int i = 1; i <= 2021; ++ i) {
//        cout << dis[i] << " ";
//    }
//    cout << endl;
    return dis[2021];
}

int main() {
    for (int i = 1; i <= 2021; ++ i) {
        for (int j = 1; j <= 2021; ++ j) {
            if (abs(i - j) <= 21) {
                add(i, j, lcm(i, j));
                add(j, i, lcm(i, j));
            }
        }
    }
    cout << dij() << endl;

    return 0;
}

F. 时间表示

思路:就是一个很简单的模拟而已

我的程序:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    ll haomiao; scanf("%lld", &haomiao);
    ll miao = haomiao / 1000;
    ll fen = miao / 60;
    ll xiaoshi = fen / 60;
    xiaoshi %= 24;
    fen %= 60;
    miao %= 60;
    printf("%02lld:%02lld:%02lld", xiaoshi, fen, miao);
    return 0;
}

G.砝码称重

思路:想了比较久的时间,想了以下最坏的情况应该是可以到2的100次,此时的元素为2的0次,2的1次直到2的100次,但是发现数据范围只有1e5。所以肯定会有很多的重复状态,考虑BFS搜索。

我的身边的人貌似都是用背包做的。

这题也算是比较可惜吧,赛中把0重量也算作可行方案。不出意外应该是爆0了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, vis[10000000], ans;
int a[100+10];

struct node {
    bitset<100> st;
    int sum;
};


void BFS() {
    queue<node> q;
    for (int i = 0; i < n; ++ i) {
        bitset<100> temp;
        temp[i] = 1;
        if (vis[a[i]] == 0) {
            q.push({temp, a[i]});
            vis[a[i]] = 1;
            ans ++;

        }
    }
    while (q.size()) {
        node cur = q.front();
        q.pop();
        for (int i = 0; i < n; ++ i) {
            node temp = cur;
            if (temp.st[i] == 0) {
                if (temp.sum + a[i] && vis[abs(temp.sum + a[i])] == 0) {
                    temp.st[i] = 1;
                    temp.sum += a[i];
                    q.push(temp);
                    vis[temp.sum] = 1;
                    ans ++;
                }
                else if (abs(temp.sum - a[i]) && vis[abs(temp.sum - a[i])] == 0) {
                    temp.st[i] = 1;
                    temp.sum -= a[i];
                    q.push(temp);
                    vis[abs(temp.sum)] = 1;
                    ans ++;
                }
            }
        }
    }

}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i) {
        scanf("%d", &a[i]);
    }
    BFS();
    printf("%d
", ans);
    return 0;
}
/*
3
1 4 6
*/

H.杨辉三角形

思路:这道题赛中只交了打表程序。估计只有20%的分。

赛后听身边的人的思路好像是是因为后面行数的杨辉三角的第三个数早就大于了1e9,所以必然只能在每行的第二个元素取到(因为杨辉三角每行的第二个数都是之前的第二个数+1,所以我们就比较容易知道了)

这里就不贴程序了。就是先打表,直到发现元素大于1e9就跳出,之后对于每个没有打表打到的数用每行的第二个数去计算即可

I.双向排序

思路:这里就只讲讲如何获得60%的分,我不清楚直接sort能不能过,因为复杂度是n * m * logn有点点卡。但是这里如果把sort换成桶排序的话就一定能获得60%的分数,因为范围非常的小,所以复杂度是O(n*m)肯定能过 60%。(等待其他的人的题解

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int a[maxn], tong[maxn];
int n, m;
bool cmp(int a1, int a2) {
    return a1 > a2;
}

void mysort(int L, int R, int flag) {
    for (int i = L; i <= R; ++ i) {
        tong[a[i]] ++;
    }
    int pos = L;
    if (flag) {
        for (int i = 1; i <= n; ++ i) {
            while (tong[i]) {
                tong[i] --;
                a[pos++] = i;
            }
        }
    }
    else {
        for (int i = n; i >= 1; -- i) {
            while (tong[i]) {
                tong[i] --;
                a[pos++] = i;
            }
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i) {
        a[i] = i;
    }
    for (int i = 1; i <= m; ++ i) {
        int opt, pos;
        scanf("%d%d", &opt, &pos);
        if (opt == 0) {
            mysort(1, pos, 0);
        }

        else if (opt == 1)
            mysort(pos, n, 1);
    }
    for (int j = 1; j <= n; ++ j) {
        if (j != 1) cout << " ";
        cout << a[j];
    }
    cout << endl;
    return 0;
}
/*
3
1 4 6
*/

I.括号序列

思路:赛场就没啥思路,直接交了一发样例。希望人没事。赛后听身边的同学说是卡特兰数,仔细想想确实是的。卡特兰数里就是有一个括号序列问题。但是我肯定不会卡特兰数啊。所以也是没办法。直接烂掉拉。

总结:这次比赛失误好多,省一估计是没了,不过大四还有一场,希望那个时候能进国赛吧。

--------------------------------------------------UPD4.29--------------------------------------------------------------

真没想到这都能有一等。国赛见

原文地址:https://www.cnblogs.com/Vikyanite/p/14673928.html