• [ZJOI2020] 序列


    Description

    给定一个长度为 (n) 的非负整数序列 (a_1,a_2,...,a_n)。每一步可以选择任意一种操作执行:

    • 选择一个区间,将其中所有数 (-1)
    • 选择一个区间,将其中所有下标为奇数的数 (-1)
    • 选择一个区间,将其中所有下标为偶数的数 (-1)

    求至少多少步能将整个序列变成 (0)

    Solution

    显然每次只需要考虑开头的相邻两位即可。

    刚开始,连直线 (min(a[1],a[2])),跳线 (a[1]-min(a[1],a[2])),这样 (a[1]) 完成。

    但后续,由于会有前面的线连过来,因此我们维护 (3) 个标记 (c_1,c_2,c_3) 分别表示从 (i-1) 连到 (i) 的直线条数,落在 (i) 上的跳线条数和落在 (i-1) 上的跳线条数。

    如果前面连过来的线过多而不能容纳,我们需要先清理掉一些,这时可能会出现一些位置不知道该留直线还是留跳线,用一个 (res) 变量记下来,之后通过等效操作将其延期处理。

    删掉被前面线覆盖掉的部分之后,计算新增的直线条数,并修改对应变量。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    int n,a[N];
    
    void solve()
    {
        memset(a,0,sizeof a);
    
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
    
        int cnt1=0;    // 直线个数
        int cnt2=0;    // 跳线个数
        int cnt3=0;    // 奇偶性为另一类的跳线个数
        int ans=0;  // 答案
        int res=0;    // 延迟标记
    
        for(int i=2;i<=n+1;i++)
        {
            // 如果前面的线过多
            if(a[i]<cnt1+cnt2)
            {
                int delta=cnt1+cnt2-a[i];         // 多余的线的数目
                if(cnt2<delta)
                    cnt1-=delta-cnt2, delta-=delta-cnt2; // 全删跳线不够,删掉一些直线
                if(cnt1<delta)
                    cnt2-=delta-cnt1, delta-=delta-cnt1; // 全删直线不够,删掉一些跳线
                // 先两边都删
                cnt2-=delta;
                cnt1-=delta;
                // 由于有了 delta 条免费线
                res=delta;
                a[i]-=delta;
            }
    
            // 删掉前面线覆盖掉的部分
            a[i]-=cnt1+cnt2;
    
            int add=min(a[i-1],a[i]); // 新增的直线的个数
    
            // 处理直线
            ans+=add;
            a[i-1]-=add;
            a[i]-=add;
            cnt1+=add;
    
            // 处理跳线
            ans+=a[i-1];
            cnt3+=a[i-1];
            a[i-1]=0;
    
            // 处理标记,留着下次决策
            a[i]+=res;    // 先把位置空出来
            ans-=res;     // 先退钱
            res=0;
    
            swap(cnt2,cnt3);
        }
    
        cout<<ans<<endl;
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--) solve();
    }
    
    
  • 相关阅读:
    linux之vi编辑器的基础命令
    redis的安装部署启动停止<17.3.21已更新>
    关于Ubuntu的ssh免密登录
    Git(管理修改)
    Git(时光机-版本回退)
    Git(查看修改记录)
    Git(创建版本库)
    集中式VS分布式
    Git(介绍和安装)
    Javascript基础知识
  • 原文地址:https://www.cnblogs.com/mollnn/p/13679532.html
Copyright © 2020-2023  润新知