CodeForces - 1372D - Omkar and Circle 前缀和(dp)

CodeForces - 1372D - Omkar and Circle 前缀和(dp)

题意:给一个奇数长度的数组,操作是选择一个位置,删除其相邻的数,并将该位置的数赋值为相邻数的和,求最终剩下的一个数字最大为多少

注意:位置1和位置n算相邻

思路及问题转化:选择某位置,表面上看删除的是相邻的两个数,但是其实总和 S S S减少的是这个位置的数,于是这个问题可以转化为:删除 n / 2 n/2 n/2个不相邻的数,剩下的数字和最大

如何去利用前缀和:在一个奇数长度的数组中删去 n / 2 n/2 n/2个数,剩余数字 n / 2 + 1 n/2+1 n/2+1个,共产生空隙 n / 2 个 n/2个 n/2,每个空隙最小为 1 1 1,故有且仅有一个空隙为 2 2 2的地方,枚举这一个空隙为2的右端数字,将其确定下来之后,其余“应当删除”的位置都确定了,计算他们的总和并取最小就行

可以先手动算几个

d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示 [ 1   i ] [1~i] [1 i]的奇数位置前缀和
d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示 [ 1   i ] [1~i] [1 i]的偶数位置前缀和
假设数组 1 2 3 4 5 6 7

删除位置组成空隙2的两个位置数组删除情况用前缀和表示删除数字的总和
16,71 2 3 4 5 6 7 d p [ n − 2 ] [ 0 ] dp[n-2][0] dp[n2][0]
27,11 2 3 4 5 6 7 d p [ n − 1 ] [ 1 ] dp[n-1][1] dp[n1][1]
31,21 2 3 4 5 6 7 d p [ i − 3 ] [ 1 ] + d p [ n ] [ 0 ] − d p [ i − 1 ] [ 0 ] dp[i-3][1]+dp[n][0]-dp[i-1][0] dp[i3][1]+dp[n][0]dp[i1][0]
42,31 2 3 4 5 6 7 d p [ i − 3 ] [ 0 ] + d p [ n ] [ 1 ] − d p [ i − 1 ] [ 1 ] dp[i-3][0]+dp[n][1]-dp[i-1][1] dp[i3][0]+dp[n][1]dp[i1][1]
53,41 2 3 4 5 6 7 d p [ i − 3 ] [ 1 ] + d p [ n ] [ 0 ] − d p [ i − 1 ] [ 0 ] dp[i-3][1]+dp[n][0]-dp[i-1][0] dp[i3][1]+dp[n][0]dp[i1][0]
64,51 2 3 4 5 6 7 d p [ i − 3 ] [ 0 ] + d p [ n ] [ 1 ] − d p [ i − 1 ] [ 1 ] dp[i-3][0]+dp[n][1]-dp[i-1][1] dp[i3][0]+dp[n][1]dp[i1][1]
75,61 2 3 4 5 6 7 d p [ i − 3 ] [ 1 ] + d p [ n ] [ 0 ] − d p [ i − 1 ] [ 0 ] dp[i-3][1]+dp[n][0]-dp[i-1][0] dp[i3][1]+dp[n][0]dp[i1][0]

代码

int n;
ll a[maxn],dp[maxn][2],cnt=0,t;
int main()
{
    scanf("%d",&n);
    rep(i,1,n)
    {
        scanf("%lld",&a[i]);
        cnt+=a[i];
        dp[i][1]=dp[i-1][1];
        dp[i][0]=dp[i-1][0];
        if (i%2==1)dp[i][0]+=a[i];
        else dp[i][1]+=a[i];
    }
    ll ans=min(dp[n-2][0],dp[n-1][1]);
//dp[n-2][0]对应的是删除位置1
//dp[n-1][1]对应的是删除位置2
    rep(i,3,n)//枚举删除位置
    {
        if (i%2==1)
        {
            t=dp[n][0]-dp[i-1][0];//右
            t+=dp[i-3][1];//左
        }
        else
        {
            t=dp[n][1]-dp[i-1][1];//右
            t+=dp[i-3][0];//左
        }
        ans=min(ans,t);
    }
    WW(cnt-ans);
    return 0;
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值