音无结弦之时,天使跃动之心。立于浮华之世,奏响天籁之音。.|

次林梦叶

园龄:3年3个月粉丝:21关注:2

2023 百度之星初赛第一场

写在前面:

  非正式题解

    具体题解处: 视频<---- 博客<----

  

公园

   

   我们可以想一下小度和度度熊一定会相遇一起走吗?

    会的,最不济的情况到最后小度和度度熊会在终点相遇

   为了总消耗最少,他们从一个点到另一个点一定是走最短路

   那他们也可能会为了相遇从而不是一口气从原点走到终点的

   于是我们可以枚举他们相遇的点,相遇后再一起走到终点

  

   于是就有个思路:

    我们求t,f,n分别到各个点的最短路,O(n)

    然后枚举相遇的点x,求最短的 t->x + f->x + x->n 的消耗

 

 


蛋糕划分

 

   基本思路就是二分,然后要多画图考虑一下细节

  首先先二分出来最重中的最轻为u

  然后check(u),看下是否有划分的方案能够达到u

   最朴素的方法就是2^2N的枚举全部方案

  但是会超时,考虑优化

  我们枚举横着切的全部方案

  然后贪心地切竖着切的方案,即我们枚举每一个竖着切的地方j

  如果在j处竖着切没有不合法,那么这一刀可有可无,因为贪心,所以我们不切着一刀

  直到不合法了,前面竖着切的那一刀一定要切,我们就记录一下

  

 

复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 20;
int n, m, g[N][N], sum[N][N];
int getS(int y1, int x1, int y2, int x2)
{
    return sum[y2][x2] - sum[y2][x1 - 1] - sum[y1 - 1][x2] + sum[y1 - 1][x1 - 1];
}
bool check(int u)
{
    // 枚举横着切,切几刀,在哪里切
    for (int i = 0; i < (1 << (n - 1)); i++)
    {
        // 比如i的二进制下的第1,3,5位为1,则说明形成了1行 2~3行 4~5行 6~n行这个几个行区间
        vector<int> row;
        int cnt = 0;
        while (cnt < n)
        {
            if ((i >> cnt) & 1)
                row.push_back(cnt + 1);
            cnt++;
        }
        if (row.size() > m)
            continue;
        row.push_back(n);
        // 然后开始贪心列的切法:
        // 假设我们将蛋糕切成了k个行区间,那么我们在列切的时候就会形成块
        // 我们的思想是维护上一次是在哪一列是一定要切的(假设为j1)
        // 枚举后面要在第几列切(假设为j)
        // 因为现在我们有k个行区间,那么会形成 k个块,这k个块的列坐标范围为j1~j
        // 如果切的块没有一个>u,说明这一列是否要切可有可无
        // 为了让通过check的机会更大,肯定是切的次数越少越好
        // 那么这一次我们就不切了
        // 直到遇到枚举到在j2列要切一刀,切出来的某块>u了,说明前面枚举的j-1是有必要要切的
        // 于是我们更新j1,然后再计算
        // 如何维护列坐标为j1~j的块的大小?开个数组rws[N]
        // [down,top]是行的区间,cowN记录一定要切的列数,lts记录上次我们某行的小块大小
        int rws[N], cowN = 0, lts[N];
        memset(rws, 0, sizeof(rws));
        bool flag = true;
        for (int j = 1; j <= n; j++)
        {
            int top, down = 1;
            cnt = 1;
            memset(lts, 0, sizeof(lts));
            for (int v : row)
            {
                top = v;
                // 现在我们求出其中一块出来
                int ts = getS(down, j, top, j);
                lts[cnt] = ts;
                if (ts > u)
                {
                    // 这个说明横切的方法不对要从新来
                    flag = false;
                    break;
                }
                // 以[j1,j]为列区间的第cnt个行区间的块的大小为rws[cnt]
                rws[cnt] += ts;
                if (rws[cnt] > u)
                {
                    // 说明前面的j-1列是一定要切的
                    cowN++;
                    // 这个时候我们需要重新更新下我们的rws[]
                    for (int k = 1; k <= row.size(); k++)
                        rws[k] = lts[k];
                }
                cnt++;
                down = top + 1;
            }
            if (!flag)
                break;
        }
        if (!flag)
            continue;
        if (row.size() - 1 + cowN <= m)
            return true;
    }
    return false;
}
int main()
{
    int l = 0, r = 1000 * N * N, ans = -1;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            cin >> g[i][j];
            l = max(g[i][j], l);
            sum[i][j] = g[i][j] + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
        }

    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid))
        {
            ans = mid;
            r = mid - 1;
        }
        else
            l = mid + 1;
    }
    cout << ans << endl;
    return 0;
}
复制代码

 

 

 

第五维度

   最晚情况的下的最早时间,二分

    写题经验告诉我要二分时间

    假设现在我得到了二分出来的时间t是最早时间

  那么这个时候智者为了不想让我们成功必然会消灭掉其中一个人类

  如果智者讲贡献最大的人类都消灭掉了但是人类还是理解了,那么我们二分出来的答案就是正确的

  如果智者消灭掉其中一个人类后,人类没有理解,说明我们二分出来的答案错误了

  我们需要增加二分出来的时间

  

流水线搭积木

  当时写的适合超时了,还死磕在那里

    不得不说,打习惯了蓝桥杯,PTA的比赛

    现在写模拟题不注意细节方面的时间复杂度倒是成了习惯

 

    写的时候不看榜单,一看发现这道题每几个人过了

    害,下次打ACM赛制还是注意一下吧

    其实卡复杂度方法就在他需要找到符合能够放积木的积木集

    这个如果暴力找会超时,要用平衡树来模拟

 

本文作者:次林梦叶

本文链接:https://www.cnblogs.com/cilinmengye/p/17612804.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   次林梦叶  阅读(729)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起