当前位置: 首页 > article >正文

12.13-12.21 刷题汇总

12.13-21刷题汇总

P1115 最大字段和

第一种 贪心法:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
ll a[200005];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    cin>>a[i];
    ll max_sum=-0x3f3f3f3f,tp_sum=-0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        if(tp_sum<0)
        tp_sum=a[i];
        else
        tp_sum+=a[i];
        if(tp_sum>max_sum)
        max_sum=tp_sum;
    }
    cout<<max_sum;
    return 0;
}

动态规划:dp[i]表示以a[i]结尾的最大子序和,那么dp[i]=max(dp[i-1]+a[i],a[i])

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
ll a[200005];
ll dp[200005];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    cin>>a[i];
    ll max_sum=-0x3f3f3f3f;
    dp[0]=a[0];
    for(int i=1;i<n;i++)
    {
        dp[i]=max((dp[i-1]+a[i]),a[i]);
        if(dp[i]>max_sum)
        max_sum=dp[i];
    }
    cout<<max_sum;
    return 0;
}

P1725 琪露诺

这题咋一看可以用BFS解决 但是没有很明显的剪枝策略 感觉时间复杂度会爆掉

先莽一波(毕竟正解是dp+单调队列)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, l, r;
ll a[200005];
ll value[200005];
queue<ll> q;
int main()
{
    cin >> n >> l >> r;
    for (int i = 0; i <= n; i++)
        cin >> a[i];
    memset(value, -0x3f3f3f3f, sizeof(value));
    q.push(0);
    value[0] = 0;
    ll max_sum = -0x3f3f3f3f;
    // for (int i = 1; i <= n; i++)
    //     cout << value[i] << ' ';
    // cout << endl;
    while (!q.empty())
    {
        ll tp = q.front();
        q.pop();
        for (int i = l; i <= r; i++)
        {
            if ((tp + i) > n) // 下一步能到河对岸
            {
                if (value[tp] > max_sum)
                    max_sum = value[tp];
                break;
            }
            if (value[tp] + a[tp + i] > value[tp + i])//如果跳到这个格子上的时候发现总能量更大,那这个格子重新入队,更新这个格子能到达的格子的value
            {
                value[tp + i] = value[tp] + a[tp + i];
                q.push(tp + i);
            }
        }
        // for (int i = 1; i <= n; i++)
        //     cout << value[i] << ' ';
        // cout << endl;
        // cout << "max_sum" << max_sum << endl;
    }
    cout << max_sum;
    return 0;
}

在这里插入图片描述

没剪枝是这样的。时间爆掉辣

回来再看一下dp+单调队列怎么写,现在去搞免修的那个表。

泰无语辣用单调队列写了好几天,最后发现是单调队列的数据结构用错了,由于单调队列要删头去尾,所以必须用双端队列,我写成普通的队列了,我说怎么一直0分。

还是简单写一下这题的思路吧

  1. 动态规划,如果跳到格子a[i]的最大价值为dp[i],我们不难发现肯定会有dp[i]一定是由能跳到a[i]的格子中的最大价值加上a[i]组成的,所以状态转移方程就是dp[i]=max{d[j]}+a[i],其中不难发现能跳到i的格子分别是i-R到i-L。
  2. 所以接下来我们把格子从1到n都扫一遍,每扫到一个元素i都会对应一个窗口(从i-R到i-L),而我们需要找到其中的最大值所以这里面很明显又可以用单调队列去优化。其中我们可以发现随着i从1到n增大,下一个入队的元素一定是i-L,所以这题单调队列的维护还是很简单的。

代码如下

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, l, r;
ll a[200005];
ll dp[200005];
deque<ll> q;
int main()
{
    cin >> n >> l >> r;
    for (int i = 0; i <= n; i++)
        cin >> a[i];
    ll ans = -0x3f3f3f3f;
    for (int i = 1; i < l; i++)//把跳不到的地方用无穷小考虑,确保不会由这些格子跳到下一个格子
        dp[i] = -0x3f3f3f3f;
    q.push_back(0);
    for (int i = l; i <= n; i++)
    {
        while (!q.empty() && dp[q.back()] < dp[i - l])
            q.pop_back();
        while (!q.empty() && q.front() < i - r)
            q.pop_front();
        q.push_back(i - l);
        dp[i] = a[i] + dp[q.front()];
        if (i + r > n)
            ans = max(ans, dp[i]);
        // for (int j = l; j <= i; j++)
        //     cout << dp[j] << ' ';
        // cout << endl;
    }
    cout << ans;
    return 0;
}

P3957 跳房子

哇呜呜 虽然这题只是二分+dp+单调队列,但是但是我debug真的花了特别特别特别久,主要是迭代mid的时候忘记初始化dp和队列q了,导致了很多错误,也简单说一下这题的思路吧

  1. 其实这题的思路和琪露诺很像,有两点要注意,第一,这题要用二分查找答案的方法找到最少的符合条件的花费;其次,这题的格子不再连续,也就是说单调队列的维护变得困难了一些,即扫描到第i个元素的时候谁入队?会不会没有元素入队?这时候我采用了用last标记最后一个未入队元素的方法来解决这个问题,随着last的递增也能确保每一个元素只入队一次,从而达到实现单调队列的目的。
  2. 此外,这题还有个很坑爹的问题,就是dp的最小值(为了防止无法到达的格子的dp值影响最后judge的判断所设置的负无穷大)要设置成-1e18,我一开始只设为-0x3f3f3f3f只能拿90分=-=

这也是第一次ac蓝题

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, d, k;
struct node
{
    ll index;
    ll value;
};
node a[500005];
ll dp[500005];
deque<ll> q;
bool judge(ll g)
{
    memset(dp, 0, sizeof(dp));
    q.clear();
    // cout << "g:" << g << endl;
    q.push_back(0);
    ll last = 1; // 目前入队的最    后一个元素的下一个元素
    ll right = g + d;
    ll left = d > g ? d - g : 1;
    for (int i = 1; i <= n; i++)
    {
        // cout << "i:" << i << endl;
        if (a[i].index < left)
            dp[i] = -1e18;
        else // 开始能跳到
        {
            ll in_scale = last;                                          // 用in_scale 找到下一个要入队的元素,即不在队列中但是能跳到i
            ll i_left = a[i].index - right, i_right = a[i].index - left; // 确定能到达i的区间范围
            while (a[in_scale].index < i_left)
            {
                in_scale++;
            }
            // cout << "inscale" << in_scale << endl;
            if (a[in_scale].index <= i_right) // 说明有新元素要入队
            {
                // cout << "haha" << endl;
                while (a[in_scale].index <= i_right)
                {
                    while (!q.empty() && dp[q.back()] < dp[in_scale])
                        q.pop_back();
                    while (!q.empty() && a[q.front()].index < i_left)
                        q.pop_front();
                    // cout<<"queue:";
                    // for(auto it : q)
                    // cout<<it<<' ';
                    // cout<<endl;
                    q.push_back(in_scale);
                    // cout << "front " << q.front() << ' ' << "dp[q.front()] " << dp[q.front()] << endl;
                    dp[i] = a[i].value + dp[q.front()];
                    // for (int i = 1; i <= n; i++)
                    //     cout << dp[i] << ' ';
                    // cout << endl;
                    if (dp[i] >= k)
                        return true;
                    in_scale++;
                }
                last = in_scale;
            }
            else // a[in_scale].index>i-d+g 下一个元素超过右端 没有元素要入队
            {
                // cout << "na" << endl;
                while (!q.empty() && a[q.front()].index < i_left)
                    q.pop_front();
                if (q.empty()) // 此时队列删头之后为空,说明无法到达
                    dp[i]=-1e18;
                else
                {
                    // cout << "front " << q.front() << ' ' << "dp[q.front()] " << dp[q.front()] << endl;
                    dp[i] = a[i].value + dp[q.front()];
                    // for (int i = 1; i <= n; i++)
                    //     cout << dp[i] << ' ';
                    // cout << endl;
                    if (dp[i] >= k)
                        return true;
                }
            }
            // cout << "last " << last << endl;
        }
    }
    return false;
}
int main()
{
    cin >> n >> d >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i].index >> a[i].value;
    ll left = 0, right = 1e9, flag = 0;
    ll g;
    while (left <= right)
    {
        ll mid = (left + right) / 2;
        if (judge(mid)) // 钱花多了
        {
            flag = 1;
            g = mid;
            right = mid - 1;
        }
        else
            left = mid + 1;
        // cout<<'b'<<endl;
    }
    // if (judge(0))
    //     flag = 1;
    if (flag)
        cout << g;
    else
        cout << -1;
    return 0;
}

P2776 小组队列

一道很简单的二维队列的题目(我还因为偷了一点小懒卡了一会哇呜呜

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, m;
ll a[100005];
queue<ll> q[305];
queue<ll> turn;
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    ll t;
    cin >> t;
    while (t--)
    {
        string op;
        cin >> op;
        if (op == "push")
        {
            ll num;
            cin >> num;
            if (q[a[num]].empty())
            {
                turn.push(a[num]);
            }
            q[a[num]].push(num);
        }
        else
        {
            ll first = turn.front();
            cout << q[first].front() << endl;
            q[first].pop();
            if(q[first].empty())
            turn.pop();
        }
    }
    return 0;
}

P2947 向右看齐

很简单的一道单调栈的题目

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
ll a[100005];
ll ans[100005];
stack<ll> st;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    ans[n] = 0;
    st.push(n);
    for (int i = n - 1; i >= 1; i--)
    {
        while (!st.empty() && a[st.top()] <= a[i])
            st.pop();
        if (st.empty())
            ans[i] = 0;
        else
            ans[i] = st.top();
        st.push(i);
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << endl;
    return 0;
}

P1739 括号表达式匹配

居然能刷到入门题

很简单的一道题 代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
string s;
stack<char> st;
int main()
{
    cin >> s;
    ll flag = 1;
    for (auto it : s)
    {
        if (it == '(')
            st.push('(');
        else if (it == ')')
        {
            if (st.empty())
            {
                flag = 0;
                break;
            }
            else
                st.pop();
        }
        else
            continue;
    }
    if(!st.empty())
    flag=0;
    if (flag)
        cout << "YES";
    else
        cout << "NO";
    return 0;
}

该有怎么样的努力才能配得上你高贵的梦想

P5018对称二叉树

这题一开始看的时候很懵逼,因为完全不知道怎么用递归去实现对于“对称”这个性质的检验,之后看了题解才恍然大悟。本题思路:

  1. 定义函数same,用于检查一个节点的左右子树是否对称,这个函数又可以分为以下几种情况来讨论:
    1. 如果左右节点都为空,那么对称
    2. 一个为空一个不为空,那么一定不对称
    3. 都不为空,检查value值是否相同,不相同一定不对称
    4. 若value值相同,那么递归检查左节点的左子树和右节点的右子树、左节点的右子树和右节点的左子树是否对称
  2. 定义函数cnt,用于统计从该节点出发的树的节点数目(这应该是常规知识)

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
struct node
{
    ll value;
    ll left, right;
};
node tree[1000005];
bool same(ll left, ll right)
{
    if (left == -1 && right == -1)
        return true;
    else if (left == -1 || right == -1)
        return false;
    else
    {
        if (tree[left].value != tree[right].value)
            return false;
        else
            return same(tree[left].left, tree[right].right) && same(tree[right].left, tree[left].right);
    }
}
ll cnt(ll x)
{
    if (x == -1)
        return 0;
    return 1 + cnt(tree[x].left) + cnt(tree[x].right);
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> tree[i].value;
    for (int i = 1; i <= n; i++)
        cin >> tree[i].left >> tree[i].right;
    ll ans = -1;
    for (int i = 1; i <= n; i++)
    {
        if (same(tree[i].left, tree[i].right))
            ans = max(ans, cnt(i));
    }
    cout << ans;
    return 0;
}

P 2168 荷马史诗

这题其实是一道比较简单的k叉哈夫曼树编码,需要用到优先队列priorty_queue。思路如下:

  1. 首先由于是k叉哈夫曼树,要确定补0的个数,观察可知每个节点都挂满的k叉哈夫曼树应该有m*(k-1)+k个节点(其中m为树深h-1),首先确定比n恰好大一点的满k叉哈夫曼树的节点数m*(k-1)+k,两者作差就能得到补0的个数。
  2. 在每次队列操作中,选择队列中最前面的k个元素组成新的节点再入队。其中为了保证树深尽量小,所以节点高度小的节点的优先级会比节点高度大的优先级更高。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, k;
struct node
{
    ll w;
    ll f;
};
class compare
{
public:
    bool operator()(node a, node b)
    {
        if (a.w > b.w)
            return true;
        if (a.w == b.w)
            return a.f > b.f;
        return false;
    }
};
priority_queue<node, vector<node>, compare> q;
ll get_num() // 要添加的0的个数
{
    ll tp = (n - k) / (k - 1);
    if (tp * (k - 1) == n - k) // 整除
        return 0;
    else
        return (k - 1) * (tp + 1) + k - n;
}
int main()
{
    cin >> n >> k;
    ll num0 = get_num();
    ll sum = 0;
    // cout << num0 << endl;
    for (int i = 0; i < num0; i++)
        q.push({0, 0});
    for (int i = 0; i < n; i++)
    {
        ll w;
        cin >> w;
        q.push({w, 0});
    }
    while (q.size() >= 2)
    {
        ll max_f = -1, tp_sum = 0;
        for (int i = 0; i < k; i++)
        {
            node p = q.top();
            q.pop();
            tp_sum += p.w;
            max_f = max(max_f, p.f);
        }
        sum += tp_sum;
        q.push({tp_sum, max_f + 1});
    }
    node ans = q.top();
    cout << sum << endl;
    cout << ans.f << endl;
    return 0;
}

http://www.kler.cn/a/446475.html

相关文章:

  • 全志H618 Android12修改doucmentsui鼠标单击图片、文件夹选中区域
  • Docker部署ant-design-pro V6.0.0
  • Fastdfs V6.12.1集群部署(arm/x86均可用)
  • 使用 UniApp 在微信小程序中实现 SSE 流式响应
  • 15.初识接口1 C#
  • 1小时放弃Rust(2): 两数之和
  • 活动预告|云原生创新论坛:知乎携手 AutoMQ、OceanBase、快猫星云的实践分享
  • 用SparkSQL和PySpark完成按时间字段顺序将字符串字段中的值组合在一起分组显示
  • mac 安装graalvm
  • 【Http,Netty,Socket,WebSocket的应用场景和区别】
  • CESS 出席华盛顿区块链政策峰会:参与国家安全与数据隐私保护专题讨论
  • BOE(京东方)“向新2025”年终媒体智享会首站落地上海 六大维度创新开启产业发展新篇章
  • 【HTML】DOCTYPE的作用?
  • SAP RESTful架构和OData协议
  • 微信小程序之今日热搜新闻
  • 【论文速读】| FirmRCA:面向 ARM 嵌入式固件的后模糊测试分析,并实现高效的基于事件的故障定位
  • 推送本地仓库到远程git仓库
  • 问题解决:发现Excel中的部分内容有问题。是否让我们尽量尝试恢复? 如果您信任此工作簿的源,请单击“是”。
  • 解析基于 SSM 框架 Vue 电脑测评系统:把握电脑测评精髓
  • Dash:数据可视化的未来之星
  • 【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
  • 用bootstrap搭建侧边栏
  • uniapp新建项目hello,什么都没干提示应用未关联服务空间,请在uniCloud目录右键关联服务空间
  • Linux中部署项目
  • 精准采集整车信号:风丘混合动力汽车工况测试
  • Solon 集成 activemq-client