【百度之星2023】初赛第一场 补题(部分)

目录

  • BD202301 公园
  • BD202302 蛋糕划分
    • 解法1
    • TODO 解法2
  • TODO BD202303 第五维度
  • TODO BD202304 流水线搭积木
  • BD202305 糖果促销

不幸因为码蹄集客户端的bug,导致没法正常参与比赛,只好事后补了

BD202301 公园

【百度之星2023】初赛第一场 补题(部分)_第1张图片
样例输入:

4 4 3
1 2 8 8
1 4
2 3
3 4
4 7
2 5
5 6
6 8
7 8

样例输出:

22

首先BFS求从小度、度度熊和终点到每个点的举距离。
然后枚举每个点,求在该点会合的答案。
O(m+n)

#include

using namespace std;
int xiaoValue, xiongValue, saveValue;
int xiao, xiong, aim;
int m;
const int N = 40000 + 100;
vector<int> e[N];
int dis[3][N];

void bfs(int id, int rt) {
    dis[id][rt] = 0;
    queue<int> q;
    q.push(rt);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (const auto &v: e[u]) {
            if (dis[id][v] > dis[id][u] + 1) {
                dis[id][v] = dis[id][u] + 1;
                q.push(v);
            }
        }
    }
}

int main() {
    cin >> xiaoValue >> xiongValue >> saveValue;
    cin >> xiao >> xiong >> aim;
    cin >> m;
    for (int i = 0, x, y; i < m; i++) {
        scanf("%d%d", &x, &y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    memset(dis, 0x3f, sizeof(dis));
    bfs(0, xiao);
    bfs(1, xiong);
    bfs(2, aim);
    using LL = long long;
    const int mx = dis[0][0];
    LL ans = LONG_LONG_MAX;
    for (int u = 1; u <= aim; u++) {
        if(dis[0][u]==mx || dis[1][u]==mx || dis[2][u]==mx){
            continue;
        }
        LL now = (LL) dis[0][u] * xiaoValue + (LL) dis[1][u] * xiongValue +
                 (LL) dis[2][u] * (xiaoValue + xiongValue - saveValue);
        ans = min(ans, now);
    }
    cout << (ans==LONG_LONG_MAX?-1:ans) << endl;
    return 0;
}

BD202302 蛋糕划分

【百度之星2023】初赛第一场 补题(部分)_第2张图片

解法1

按位枚举横切,dp处理纵切。
dp[已划分段数][截止位置]。dp[0][0]=0,其它dp[i][j]=INF。
枚举之前的截止位置,从(已划分段数-1)和之前的截止位置和新一段若干块的最大值,对枚举得到的所有结果求最小值。
O(n^4*2^(n-1))
按说过不了,但实际能过,可能实际比较“稀疏”,所以常数比较小。
应该可以进一步预处理成O(n^3*2^(n-1))

#include

using namespace std;
const int N = 15;
const int NN = 35;
int n, k;
int mp[NN][NN], s[NN][NN];

inline int getSum(int xl, int xr, int yl, int yr) {
    return s[xr][yr] - s[xl - 1][yr] - s[xr][yl - 1] + s[xl - 1][yl - 1];
}

int cal(vector<int> &pos, int l, int r) { // O(n)
    int mx = 0;
    for (int i = 1; i < pos.size(); i++) {
        mx = max(mx, getSum(pos[i - 1] + 2, pos[i] + 1, l, r)); // 0 1
    }
    if (!pos.empty()) {
        int fst = getSum(1, pos.front() + 1, l, r);
        int lst = getSum(pos.back() + 2, n, l, r);
        mx = max(mx, max(fst, lst));
    } else {
        int all = getSum(1, n, l, r);
        mx = max(mx, all);
    }
    return mx;
}

inline int work(vector<int> &pos, int rest) {
    int dp[NN][NN];
    memset(dp, 0x3f, sizeof(dp));
    dp[0][0] = 0;
    ++rest;
    for (int i = 1; i <= rest; i++) { // O(n^3)
        int ed = n - (rest - i);
        for (int j = i; j <= ed; j++) {
            for (int p = i - 1; p < j; p++) {
                if (dp[i - 1][p] < dp[i][j]) {
                    int now = cal(pos, p + 1, j);
                    dp[i][j] = min(dp[i][j], max(dp[i - 1][p], now));
                }
            }
//            printf("dp[ %d ][ %d ] = %d\n", i, j, dp[i][j]);
        }
    }
    return dp[rest][n];
}

int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> mp[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + mp[i][j];
        }
    }
    int ans = 1000 * 20 * 20;
    for (int i = 0; i < (1 << (n - 1)); i++) { // O(2^(n-1))
        vector<int> pos;
        {
            for (int p = 0; (1 << p) <= i; p++) {
                if (i & (1 << p)) {
                    pos.push_back(p);
                }
            }
        }
        if (pos.size() > k) {
            continue;
        }
        int now = work(pos, k - pos.size());
//        printf("%o: %d\n", i, now);
        ans = min(ans, now);
    }
    cout << ans << endl;
    return 0;
}

TODO 解法2

枚举横切,然后二分答案,每次划分尽可能推迟到较靠后的位置。

TODO BD202303 第五维度

TODO BD202304 流水线搭积木

BD202305 糖果促销

【百度之星2023】初赛第一场 补题(部分)_第3张图片

3
3 4
4 5
2 7
3
4
4

至少要买一颗糖果。用糖纸换的不需要买。
小心负数被除会向负无穷取整。

#include

using namespace std;

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int p, k;
        scanf("%d%d", &p, &k);
        if (k == 0) {
            puts("0");
        } else {
            printf("%d\n", k - (k - 1) / p);
        }
    }
    return 0;
}

你可能感兴趣的:(ACM,C++,算法,c++)