一道很水的dp题
题目描述:
在 Farmer John 最喜欢的节日里,他想要给他的朋友们赠送一些礼物。由于他并不擅长包装礼物,他想要获得他的奶牛们的帮助。你可能能够想到,奶牛们本身也不是很擅长包装礼物,而 Farmer John 即将得到这一教训。
Farmer John 的 N 头奶牛(1≤N≤10^4)排成一行,方便起见依次编号为 1…N。奶牛 ii 的包装礼物的技能水平为 si。她们的技能水平可能参差不齐,所以 FJ 决定把她的奶牛们分成小组。每一组可以包含任意不超过 K 头的连续的奶牛(1≤K≤10^3),并且一头奶牛不能属于多于一个小组。由于奶牛们会互相学习,这一组中每一头奶牛的技能水平会变成这一组中水平最高的奶牛的技能水平。
请帮助 FJ 求出,在他合理地安排分组的情况下,可以达到的技能水平之和的最大值。
样例:
输入:输入的第一行包含 N 和 K。 输出:输出 FJ 通过将连续的奶牛进行分组可以达到的最大技能水平和。
以下 N 行按照 N 头奶牛的排列顺序依次给出她们的技能水平。 84
技能水平是一个不超过 10^5 的正整数。
7 3 1 15 7 9 2 5 10
思路:
显然,这是一道dp,数据较小,n≤10^4,O(n²)可以过。
于是我们设f[i]为从1到i最大的技术水平和,j为从i到i-j+1位一组,
maxn为s[1]到s[i]最大的技术水平。
转移同时max当前s[j]和maxn;
自然而然地想到转移方程
f[i]=max(f[i],f[i-(i-j+1)]+maxn*(i-j+1));
不需要优化和卡常(水)
但我在考场上没想到是一道dp,以为是贪心。
代码
#include<cstdio> #include<iostream> using namespace std; int n,k,s[10100],f[10100]; int main() { // freopen("teamwork.in","r",stdin); // freopen("teamwork.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1; i<=n; ++i) scanf("%d",&s[i]); for (int i=1; i<=n; ++i) { int maxn=-1; for (int j=i; j>=1&&j>i-k; --j) { maxn=max(maxn,s[j]); f[i]=max(f[i],f[i-(i-j+1)]+maxn*(i-j+1)); } } printf("%d",f[n]); }