青鸹(?)

link

显然两个数要对答案产生贡献,二者之间的数的个数必为奇数,如果是偶数,就不能仅删除中间的部分。

手模后发现,设对答案产生贡献的数为 a p 1 , a p 2 , … , a p k a_{p_1},a_{p_2},\dots,a_{p_k} ap1,ap2,,apk p 1 ≡ p 2 ≡ ⋯ ≡ p n ( m o d 2 ) p_1\equiv p_2\equiv\dots\equiv p_n\pmod 2 p1p2pn(mod2)

所以最优策略是在奇数或偶数位置选全部正数,然后确定了选的数后,把相邻两个数之间的连续段删去即可,发现中间的最小操作次数就是连续段长度除以 2 2 2,两边的段单独求。

特判序列全部都是负数的情况。

时间复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define dis(x) (x>1?(x+1>>1):0)
constexpr ll INF=1e18;
const int N=1e6+1;
int n,cnt1,cnt2;
ll ans1,ans2,a[N];
struct node
{
    ll x,i;
}b1[N],b2[N];
int main()
{
    freopen("friends.in","r",stdin);
    freopen("friends.out","w",stdout);
    cin.tie(0)->sync_with_stdio(0);
    int fl=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(i&1) b1[++cnt1]={a[i],i};
        else b2[++cnt2]={a[i],i};
        if(a[i]>0) fl=1;
    }
    if(!fl){
        ll maxn=-INF,maxi;
        for(int i=1;i<=n;i++){
            if(maxn<a[i]){
                maxn=a[i];
                maxi=dis(i)+dis(n-i+1);
            }
            else if(maxn==a[i]) maxi=min(maxi,1ll*dis(i)+dis(n-i+1));
        }
        cout<<maxn<<"\n"<<maxi;
        return 0;
    }
    ll maxi=-INF,mini=INF,sum=0;
    for(int i=cnt1;i>=1;i--){
        if(b1[i].x<=0) continue;
        sum+=b1[i].x;
        maxi=max(maxi,b1[i].i);
        mini=min(mini,b1[i].i);
    }
    ans1=sum,ans2=(maxi-mini)/2+dis(mini)+dis(n-maxi+1);
    sum=0,maxi=-INF,mini=INF;
    for(int i=cnt2;i>=1;i--){
        if(b2[i].x<=0) continue;
        sum+=b2[i].x;
        maxi=max(maxi,b2[i].i);
        mini=min(mini,b2[i].i);
    }
    if(ans1<sum) ans1=sum,ans2=(maxi-mini)/2+dis(mini)+dis(n-maxi+1);
    else if(ans1==sum) ans2=min(ans2,(maxi-mini)/2ll+dis(mini)+dis(n-maxi+1));
    cout<<ans1<<"\n"<<ans2;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值