jzoj5408 【NOIP2017提高A组集训10.21】Dark (巧设状态的DP)

题面

LichKing 希望收集邪恶的黑暗力量,并依靠它称霸世界。
世间的黑暗力量被描述成一个长度为N 的非负整数序列{Ai},每次它可以选择这个序列中的两个相邻的正整数,让他们的值同时减一并获得一点邪恶力量,直到不存在满足条件的数。
然而你不希望他能够得逞,所以你会使得他收集的能量尽可能少。
这里写图片描述

分析

考虑从左到右搞,发现你只需要知道上一个剩余多少与上上个是否还有,就可以选择去除多少个,上一个是否必须清完。 比赛时没想到是因为不知道如何设状态。想了设f[i][j]的,但是不知怎地认为转移需要二维…

发现当前状态可以划分为f[i][j][0/1]表示当前剩余j个,上个是否用完,这样1..i搞完的最小代价(没有相邻的1,除了最后两个位置)。
f[i][j][0]=f[i1][a[i]j][0/1]+a[i]j
f[i][j][1]=f[i1][j][0]+a[i]j,       j>a[i]j
答案就是f[n][x][0]或f[n][0][1]
加上后缀min优化,时间O(sigma ai)

Demo

#include <cstdio>
#include <iostream>
#include <cstring>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N = 1e5+10;

int n,ans;
int a[N],f[2][5000010][2],g[2][5000010],o;

int main() {
    freopen("dark.in","r",stdin);
    //freopen("dark.out","w",stdout);
    cin>>n; for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    memset(f,127,sizeof f);
    f[o][0][0]=0;
    for (int i=1; i<=n; i++) {
        o=1-o;
        for (int j=0; j<=a[i]; j++) {
            if (a[i]-j<=a[i-1]) 
                f[o][j][0]=min(f[1-o][a[i]-j][1],f[1-o][a[i]-j][0])+a[i]-j;
            else f[o][j][0]=1<<30;

            if (a[i]-j+1<=a[i-1])
                f[o][j][1]=g[1-o][a[i]-j+1]+a[i]-j;
            else f[o][j][1]=1<<30;
        }
        g[o][a[i]+1]=1<<30;

        for (int j=a[i]; j>=0; j--) 
            g[o][j]=min(f[o][j][0],g[o][j+1]);
    }
    cout<<min(f[o][0][1],g[o][0])<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值