//本总结仅代表个人观点,有不同意见欢迎发表评论

1、冶炼金属

        这道题的难度是比较低的,通过样例说明可以基本了解到这道题目的规律,但是我在第一次写这道题目的时候只拿了6分,原因是踩到了一个坑点(可能也不算坑点,就是我有点想当然了)。

        这道题要求的最大值是min(Ai/Bi),其中(Ai/Bi)是向下取整的,由于c++中'/'本身就是向下取整的含义所以无需有更多的操作。

        但是最小值是max(Ai/(Bi+1)),其中(Ai/(Bi+1))是向上取整的,注意这里不是四舍五入而是向上取整(比如Ai=60,Bi=2的情况,此时Ai/(Bi+1)是20,如果不向上取整且此时20是最大值,那么这个最大值就会导致V取最小值时Ai金属炼制数目与Bi不一致)。注意四舍五入是+0.5,向上取整是+1(我就倒在了这里,心痛)。

代码指路:https://blog.csdn.net/nintenkou/article/details/159822251?fromshare=blogdetail&sharetype=blogdetail&sharerId=159822251&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

2、飞机降落

        这道题我也是只拿了4分(没错,就是非常之菜)。这道题其实就是一个dfs的模板题,但是要注意的是在dfs搜索的时候,前一个飞机继承给当前飞机的时间并不一定是当前飞机实际到达时间(没错,博主又是哐哐跳进了这个大坑),所以在遍历的时候当前飞机的开始时间一定要取max(前一个飞机继承给当前飞机的时间,当前飞机到达时间)!!!!!!

        也是在这里哐哐丢分丢到心痛,前两题直接战损了一半多的分,博主看完解析之后以及属于是肠子都悔青了的状态,还好打的是练习赛qwq。

代码指路:

https://blog.csdn.net/nintenkou/article/details/159823532?fromshare=blogdetail&sharetype=blogdetail&sharerId=159823532&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

3、接龙数列

        这道题本博主终于是硬朗起来了,直接就是15分全部拿下。

        这道题感觉有点线性dp的味道,不过其实非常之简单。虽然题目的A在[1,1e9]的范围内,但其实我们需要的只有A的第一个数字和最后一个数字,所以Ai直接用字符串cin就可以了,cin会为你屏蔽到无用的空格,并把独立的字符串递到你的手上。

        那么我们在读入一个独立的字符串之后,就能很轻易地通过下标找到字符串的第一个数字a和最后一个数字b,此时我们需要一个长度为10,下标为0-9的数组qw存储以b结尾的接龙序列的最大长度,当字符串的最后一个数字为b时,此时qw[b]=max(qw[a]+1(由于是以a打头的字符串,所以应该与以a结尾的接龙序列对接),qw[b]);

        最后在遍历一遍0-9找到最长的那个接龙数列即可。

代码指路:

https://blog.csdn.net/nintenkou/article/details/159823825?fromshare=blogdetail&sharetype=blogdetail&sharerId=159823825&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

4、岛屿个数

        这题本博主不出意料的被0封了(事后发现其实是循环写的有一点点小问题。。。,我想我真该去练练了)。

        这道题的难点其实就在于子岛屿的问题,但其实仔细想想,所谓子岛屿就是被包裹在另一个岛屿里面,是一定碰不到外海的,而如果不是子岛屿,就可以碰到外海。

        所以这道题关键点就是写一个函数判断当前为1的点是否可以碰到外海,如果可以,则说明不是子岛屿,如果不是子岛屿,在沿着和他相邻的1进行一次标记即可。注意在判断外海的时候要遍历8个方向,比如碰到:

        

这种情况的时候,只判断4个方向是完全不够的。        

代码如下:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 55;
char a1[N][N];
int vis[N][N];
int sx = -1, xxx = 0x3f3f3f3f, sy = -1, xy = 0x3f3f3f3f;
int direct[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
int n, m;
void dfs(int x, int y)//对相邻连通块进行标记
{

    for (int i = 0; i < 4; i++)
    {
        int xx = x + direct[i][0], yy = y + direct[i][1];
        if (xx<1 || xx>n || yy<1 || yy>m || vis[xx][yy] || a1[xx][yy] != '1')
            continue;
        vis[xx][yy] = 1;
        dfs(xx, yy);
    }
}
bool vis1[100][100];
int direct2[8][2] = { {-1,0},{1,0},{0,-1},{0,1},{1,-1},{-1,-1},{1,1},{-1,1} };//注意子岛屿判断一定要是8方向
bool f1(int x, int y)//判断是否是子岛屿
{
    queue<pair<int, int>> k;
    k.push({ x, y });
    vis1[x][y] = 1;
    while (!k.empty())
    {
        auto p = k.front();
        k.pop();
        for (int i = 0; i < 8; i++)
        {
            int xx = p.first + direct2[i][0];
            int yy = p.second + direct2[i][1];
            if (xx < 1 || xx > n || yy < 1 || yy > m )
                return false;
            if (vis[xx][yy]||vis1[xx][yy])
                continue;
           
            vis1[xx][yy] = 1;
            k.push({ xx,yy });
        }
    }
    return true;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        memset(a1, 0, sizeof(a1));
        memset(vis, 0, sizeof(vis));
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                cin >> a1[i][j];
            }
        }
        int sum = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                if (a1[i][j] == '0')
                    continue;
                if (vis[i][j])
                    continue;
                memset(vis1, 0, sizeof(vis1));
                if (f1(i, j))
                    continue;
                
                dfs(i, j);
                sum++;
            }
        }
        cout << sum << endl;
    }
}

5、子串简写

        这道题本博主也是成功拿下了18分,但其实博主18分的答案是想的太多了。

        这道题其实就是非常非常基础的前缀和的题目,步骤如下:

                1、通过遍历得到到si点的c1字符串个数。

                2、然后再遍历一遍s字符串,当si为c2时,前缀和数组中i-k+1的位置就是以c1开头,当前i下标c2结尾的所有字串个数

        最后直接输出答案就可以啦

代码指路:
 

https://blog.csdn.net/nintenkou/article/details/159856915?fromshare=blogdetail&sharetype=blogdetail&sharerId=159856915&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

6、整数删除

        这道题本博主以一个非常狼狈的姿态拿下了4分,剩下的都超时了。

        这道题本质上不难的,考了一个模拟链表+找一个最小的值(小根堆可以非常轻松的找最小的值,但是博主写的时候并没有想到)

        模拟链表是因为数组在做完每一次删除操作后,元素个数和值都在更新,因此我们需要和数组一起不断地更新更新更新。如果用静态数组的话更新数组个数以及值是非常困难的,动态数组的查找和删除也是非常耗费时间的,因此我们就想到了对于删除操作只需要O(1)时间复杂度的链表。

        我们把当前数组中所有的值打入到一个priority_queue(小根堆)中,帮助我们找到当前数组的最小值。另外还需要开一个数组vis,如果vis是不为0的,表示我找到的这个最小值被+了一个数,那么操作之后再次入队即可,这个操作是为了让元素的当前状态与小根堆里的状态保持一致。

        注意在元素个数到达n-k之后,对小根堆里的数据再一次进行遍历直到小根堆为空,防止有的数据未被更新到最新状态,最后输出即可。

代码指路:

     https://blog.csdn.net/nintenkou/article/details/159856969?fromshare=blogdetail&sharetype=blogdetail&sharerId=159856969&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

(怎么还有两道题,博主写到这里的时候其实CPU已经快燃尽了)

7、景区导游

        这道题博主在写的时候成功骗下7分,但其实正解与主包毫无关系

         也是在这道题里LCA正式亮相,对于这种跳来跳去跳上跳下的题目都可以考虑是否可以用LCA(最近公共祖先)解题。LCA非常重要的组成部分就是:
        1、用dfs求个点到根节点的距离

        2、一个lca子函数求两点间的LCA,对于这个lca子函数,先跳到同一深度,判断同一深度时父节点是否相等,不相等再次20-0跳,找相同父节点。

        写完这两个函数之后,求原定游览路线的总长,然后再对Ai依次操作即可,详情请看代码,主包已经无力书写:

        https://blog.csdn.net/nintenkou/article/details/159881591?fromshare=blogdetail&sharetype=blogdetail&sharerId=159881591&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

8、砍树

        砍树与景区导游是比较相似的,都用到了LCA,不太一样的是砍树还用到了边的差分,如果边的差分数组在i位置上是m(即应断掉的边的个数),说明当前节点连通了应该断掉的m个节点,那么该点就是答案之一(注意答案取编号max)

      代码指路:

https://blog.csdn.net/nintenkou/article/details/159882706?fromshare=blogdetail&sharetype=blogdetail&sharerId=159882706&sharerefer=PC&sharesource=nintenkou&sharefrom=from_link

        

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐