5408.Dark

愣是弄不出T3&T4了……
感觉T4有点像上次的T2灌水?但是要前缀和?


Description

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

Input

N
A1 A2 … AN

Output

输出一行一个整数,表示答案。

Sample Input

10
2 0 1 2 0 0 0 0 0 0

Sample Output

1

Data Constraint

在这里插入图片描述


还是论第一直觉,我想到的是DP。
所以开始设状态、推式子,但是1小时后无果,果然题目看似简单其实难得一批。
再看一下题目大意,每次选两个挨在一起得正整数,并且都减去他们中最小的那一个。然后问你要多少次可以消完。

所以,如何DP呢?考虑一维的线性方法:
首先是第一种
1 1
两个连着的都取的话,就变成了 0 0
式子 f i − 1 + a i f_{i-1}+a_{i} fi1+ai

然后是第二种
中间隔了一个不取的话
1 0 1
成了
0 0 0
式子 f i − 2 + a i f_{i-2}+a_{i} fi2+ai

最后是玄学的第三种
要是空两个取的话
1 0 0 1
要变成
0 0 0 0
i-1&i只能都去完,才能保证合法
所以式子 f i − 3 + m a x ( a i − 1 , a i ) f_{i-3}+max(a_{i-1},a_{i}) fi3+max(ai1,ai)
但是,因为特殊性。我们要取到n+1这个位置才能找到正确的答案。

但是,我把这三个式子压成了一个式子。因为我们可以将整体的序列往后移2位,这样就只有一个式子啦。

#include<cstdio>
#include<cstring>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define cin(x) scanf("%lld",&x);
using namespace std;
long long n;
long long a[1000005],f[1000005];
long long max(long long x,long long y){if(x>y) return x;return y;}
long long min(long long x,long long y){if(x<y) return x;return y;}
int main()
{
	fre(dark);
	cin(n);n+=3;
	for(long long i=3;i<n;++i) cin(a[i]);
	for(long long i=3;i<=n;++i) f[i]=min(f[i-2]+a[i],f[i-3]+max(a[i-1],a[i]));
	printf("%lld",f[n]);
	return 0;
}

或者

#include<bits/stdc++.h>
using namespace std;
int n,i,j,a[1111111],f[1111111],ans;
int main()
{
	freopen("dark.in","r",stdin);
	freopen("dark.out","w",stdout);
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	f[1]=a[1];
	f[2]=a[2];
	for(i=3;i<=n;i++)
	{
		f[i]=min(f[i-1]+a[i],f[i-2]+a[i]);
		f[i]=min(f[i],f[i-3]+max(a[i-1],a[i]));
	}
	ans=min(f[n],f[n-1]);
	cout<<ans<<endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值