cf1373 Educational Round 90 Div.2-D【差分+思维】

Date:2022.01.03

题意:假设下标从1开始,只能翻转一次某一子序列,求下标为奇数的最大和。
在这里插入图片描述

思路①:首先显然交换的区间长度为奇数是没有意义的,因此如果交换区间长度只能固定为偶数。模拟一下不难发现翻转本质是让一个区间的值从奇数项和变为偶数项和,因此只需要找到偶数项和 - 奇数项和值最大的那个区间即可,我们先暴力试一下。
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
typedef unsigned long long LL;
LL t,n,m,k;
LL a[N],b[N];
LL sumji[N],sumou[N];
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--)
    {
        LL sums=0;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(i%2) 
            {
                sums+=a[i];
                sumji[i]=sumji[i-1]+a[i];
                sumou[i]=sumou[i-1];
            }
            else
            {
                sumji[i]=sumji[i-1];
                sumou[i]=sumou[i-1]+a[i];
            }
        }
        LL res=sums;
        for(int i=2;i<=n;i+=2)//选定长度
        {
            for(int l=1;l<=n-i+1;l++)//起始点
            {
                LL r=l+i-1;
                LL sumj=sumji[r]-sumji[l-1];
                LL sumo=sumou[r]-sumou[l-1];
                LL summ=sums-sumj+sumo;
                res=max(res,summ);
            }
        }
        cout<<res<<endl;
    }
    return 0;
}

然而会t掉。
在这里插入图片描述

思路②:大体思路是没有错的,不过在统计哪个区间的奇数和 - 偶数和最大时,沿用了“最大子段和”的思想。因为每个区间值的转换原理都是奇数和->偶数和,因此我们用差分数组表示每个奇数项 - 偶数项,取区间和即为 + 若干偶数项 and - 若干奇数项,用一个当前和记录每一步的和。当前和<0时,表示当前区间已不能选,当前和置为0并继续向后取【说不太清楚,自己模拟一下吧…】。除此之外,奇数项 - 偶数项有两种,一种奇数项 - 前面的偶数项,另一种是奇数项 - 后面的偶数项,因此处理两次。
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
typedef long long LL;
LL t,n,m,k;
LL a[N],b[N];
LL l[N],r[N];
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--) 
    {
        LL sum=0,res=0;
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>a[i];
            if(i%2) sum+=a[i];
        }
        LL now=0;
        for(int i=2;i<=n;i+=2)
        {
            now+=a[i]-a[i-1];
            res=max(res,now);
            if(now<0) now=0;
        }
        now=0;
        for(int i=3;i<=n;i+=2)
        {
            now+=a[i-1]-a[i];
            res=max(res,now);
            if(now<0) now=0;
        }
        cout<<sum+res<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值