首页 > 其他分享 >从CF1373D看最大子段和与奇偶段的分析

从CF1373D看最大子段和与奇偶段的分析

时间:2024-03-28 19:13:09浏览次数:26  
标签:std 奇偶 pre 子段 auto 枚举 CF1373D mxPre

Problem - 1373D - Codeforces

先看出了一个很显然的东西,逆转的子序列的长度必须是偶数。

但之后就想错了,想到双指针和其他方法去求这个最大段。

但我粗暴的通过 \(a_{i + 1} - a_i\) 来贪心双指针明显是不对的。

最大子段和

只要把 \(a_{i + 1} - a_{i}\) 转成一个数组 \(b_i\),发现问题就转化成了经典问题最大子段和

求一个序列连续段的最大和。

利用 dp 思想,设加上当前这个数之后,前缀和为 \(SUM\)

如果 \(SUM \ge 0\),那么这个前缀仍然可能贡献最大答案,加上这个数没问题。

如果 \(SUM < 0\),那么这个前缀还不如不选得到的 \(0\),\(SUM \gets 0\)

然后每一次都更新答案。

for (auto& x : a) {
	sum += x;
    if (sum < 0) {
        sum = 0;
    }
    ans = std::max(ans, sum);
}

奇偶段问题

但我们发现如果只从 \(i = 0\) 开始枚举段样例都过不了。

这是因为这类枚举奇\偶段问题要分两次枚举才能枚举完所有奇偶段

  • 从 \(0\) 开始枚举完
  • 从 \(1\) 开始枚举完

这是很显然的,比如:

1 3 4 5 6 7

显然我们要包括所有偶数段,如果只从 0 开始

1 3, 1 3 4 5, 1 3 4 5 6 7

少了一些段,所以还要再从 \(1\) 开始

3 4, 3 4 5 6

代码实现

void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (auto& x : a) std::cin >> x;
    i64 ans{};
    for (int i = 0; i < n; i++) {//先把原来偶数位上都加起来
        if (i % 2 == 0) {
            ans += a[i];
        }
    }
    
    i64 mxPre{};

    auto getMxPre = [&](auto& a) -> void {//最大子段和问题
        i64 pre{};
        i64 _mxPre{};
        for (auto& x : a) {
            pre += x;
            if (pre < 0) {
                pre = 0;
            }
            _mxPre = std::max(_mxPre, pre);
        }
        mxPre = std::max(mxPre, _mxPre);
    };

    std::vector<int> deal0, deal1;

    for (int i = 0; i + 1 < n; i += 2) {
        deal0.push_back(a[i + 1] - a[i]);
    } 

    for (int i = 1; i + 1 < n; i += 2) {
        deal1.push_back(a[i] - a[i + 1]);//这里是因为从1开始枚举每次开头的都是奇数
    }
    
    getMxPre(deal0); getMxPre(deal1);

    std::cout << ans + mxPre << '\n';
}

标签:std,奇偶,pre,子段,auto,枚举,CF1373D,mxPre
From: https://www.cnblogs.com/kdlyh/p/18102425

相关文章

  • P1121 环状最大两段子段和
    原题链接题解这里和线性最大两段子段和不同,没有子段之间必须间隔一米,所以处理方式略有不同code#definelllonglong#include<bits/stdc++.h>usingnamespacestd;lla[200005]={0},pre[200005]={0},suf[200005]={0};intmain(){ios::sync_with_stdio(false);......
  • Java 编程实例:相加数字、计算单词数、字符串反转、元素求和、矩形面积及奇偶判断
    Java如何相加两个数字相加两个数字示例intx=5;inty=6;intsum=x+y;System.out.println(sum);//打印x+y的和输出11解释首先,声明两个int类型的变量x和y,并分别赋值为5和6。然后,使用+运算符将x和y相加,并将结果赋给变量sum。最后,使用Sy......
  • 浅谈奇偶校验
    奇校验:"1"的个数为奇数偶校验:"1"的个数为偶数(补充的1位校验码放在前后其实都可以,这里是往后面放)比如001的奇校验0010,偶校验0011比如010的奇校验0100,偶校验0101比如011的奇校验0111,偶校验0110简简单单,但是为什么奇偶校验的码距是2呢?首先需要知道码距是什么定......
  • 6-12 奇偶分离排序(关注输出的空格处理)
    6-12奇偶分离排序(关注输出的空格处理)分数10作者王秀单位福州大学输入10个整数,完成一个函数使数据重新排序以后输出(也按空格分隔),要求:输出奇数在前偶数在后函数接口定义:voidsort_tarray(int*a);裁判测试程序样例:#include<cstdio>#include<iostream>#inclu......
  • 蓝桥杯2020决赛:试题 I 奇偶覆盖
    原题如果不考虑奇偶性,其实就是扫描线的板子。考虑如何处理奇偶:首先在线段树存两个变量\(len_1\)以及\(len_2\),分别表示奇长度和偶长度。再用\(sum\)记录当前两个端点之间被覆盖了多少次。然而我们无法直接获得每一个子区间的具体覆盖数目。所以从奇偶性的特点方面入手。......
  • 【力扣】奇偶链表
    题目描述思路我想起了一位故人。。前面那道分隔链表的题,只需要把<x的条件改为位置的奇偶即可完全照搬过来,出题人偷懒了属于是。试着不抄代码重新写一遍:简单写了一下发现这道题不太适合用递归算法求解,因为结点在整个链表中的位置不太好确认,试着用双指针法写一下:classSolut......
  • 最大子段和
    这道题目跟“生日礼物”非常像,但这里必须刚好选择\(m\)个,为了没有歧义,我们认为两个不同子段一定不会挨着(就是中间必须有数)这个状态具体一下:一定要选择第\(j\)个数但其实我觉得这个方程是有一点问题的,\(k\)应该从\(j-2\)开始减接下来考虑优化空间在考虑优化时间然后这道题......
  • Codeforces Round 770 (Div. 2)(数学异或奇偶性)
    B.FortuneTelling拿到题目看数据范围之后就知道暴力显然是来不及的。那么只能找性质。\(考虑x和x+3的不同\quad奇偶性不同\)\(然后考虑两种操作对于一个数的奇偶性的影响\)\(加法:同奇偶则运算结果是偶,不同则运算结果为奇\)\(异或:惊奇的发现异或也是这样的\)这样我们就......
  • map|动态规划|单调栈|LeetCode975:奇偶跳
    作者推荐【贪心算法】【中位贪心】.执行操作使频率分数最大涉及知识点单调栈动态规划map题目给定一个整数数组A,你可以从某一起始索引出发,跳跃一定次数。在你跳跃的过程中,第1、3、5…次跳跃称为奇数跳跃,而第2、4、6…次跳跃称为偶数跳跃。你可以按以下方式从索引i向后跳转......
  • 傅里叶级数@正弦级数和余弦级数@奇偶延拓和周期延拓
    文章目录abstract正弦级数和余弦级数周期延拓奇偶延拓对延拓函数做区间限制小结偶延拓方法奇延拓方法例abstract傅里叶级数@正弦级数和余弦级数@奇偶延拓和周期延拓正弦级数和余弦级数奇函数的傅里叶级数是只含有正弦项的正弦级数偶函数的傅里叶级数是只含有余弦项的余弦级数准确......