JZOJ 5408 【NOIP2017提高A组集训10.21】Dark

Dark

Description

一个长度为 n 的非负整数序列A,每次可以选择这个序列中的两个相邻的正整数,让他们的值同时减1,不停操作直到不存在满足条件的数。
问最少的操作次数。

Data Constraint

这里写图片描述

Solution

我们记状态 f [i][ j ][0/ 1 ]表示第i个数的当前值为 j ,它的上一个值是否为0的最少操作次数。
发现这样子转移到的状态只与当前状态有关,再维护一个后缀最值转移即可。
方程转移式很容易推,实在不懂可以看看标程。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)

using namespace std;
typedef long long ll;
const ll N=11e4,M=11e5;
int f[2][M][2],a[N],q[N],g[M];
int n,m,j,k,l,i;

void read(int &o)
{
    o=0; char ch=' ';
    for(;ch<'0'||ch>'9';)ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
}

int min(int a,int b)
{if(a<b)return a;else return b;}

int max(int a,int b)
{if(a>b)return a;else return b;}

int main()
{
    cin>>n;
    fo(i,1,n)read(a[i]),q[i]=q[i-1]+a[i];
    int u=0,v;
    fo(i,1,n)
    {
        v=1-u;
        fo(l,0,a[i])f[v][l][0]=f[v][l][1]=2*q[n];
        g[a[i-1]+1]=q[i-1]/2+2;
        fd(l,a[i-1],0)g[l]=min(g[l+1],f[u][l][0]);
        fo(l,max(0,a[i]-a[i-1]+1),a[i])
        f[v][l][1]=g[a[i]-l+1]+a[i]-l;
        fo(l,0,min(a[i-1],a[i]))
        f[v][a[i]-l][0]=min(min(f[u][l][0],f[u][l][1])+l,f[v][a[i]-l][0]);
        u=v;
    }
    int ans=q[n]/2;
    fo(i,0,a[n])ans=min(ans,f[u][i][0]);
    ans=min(ans,f[u][0][1]);
    printf("%d",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值