poj 3186 Treats for the Cows(区间dp)

Treats for the Cows

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 4375   Accepted: 2226

Description

FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast amounts of milk. FJ sells one treat per day and wants to maximize the money he receives over a given period time.

The treats are interesting for many reasons:

  • The treats are numbered 1..N and stored sequentially in single file in a long box that is open at both ends. On any day, FJ can retrieve one treat from either end of his stash of treats.
  • Like fine wines and delicious cheeses, the treats improve with age and command greater prices.
  • The treats are not uniform: some are better and have higher intrinsic value. Treat i has value v(i) (1 <= v(i) <= 1000).
  • Cows pay more for treats that have aged longer: a cow will pay v(i)*a for a treat of age a.

Given the values v(i) of each of the treats lined up in order of the index i in their box, what is the greatest value FJ can receive for them if he orders their sale optimally?

The first treat is sold on day 1 and has age a=1. Each subsequent day increases the age by 1.

Input

Line 1: A single integer, N

Lines 2..N+1: Line i+1 contains the value of treat v(i)

Output

Line 1: The maximum revenue FJ can achieve by selling the treats

Sample Input

5
1
3
1
5
2

Sample Output

43

Hint

Explanation of the sample:

Five treats. On the first day FJ can sell either treat #1 (value 1) or treat #5 (value 2).

FJ sells the treats (values 1, 3, 1, 5, 2) in the following order of indices: 1, 5, 2, 3, 4, making 1x1 + 2x2 + 3x3 + 4x1 + 5x5 = 43.

题目要求从两边取,权值为a[i]*cnt,这样就很不好处理。

假设从里面往外取,取最里面的那个权值为a[i]*n,倒数第二个为a[j]*(n-1),

dp[i][j]表示取完[i,j]区间的最大值,那么由dp[i][i]很容易得到dp[i][i+1];

dp[i][j]=max(dp[i+1][j]+a[i]*cnt,dp[i][j-1]+a[j]*cnt);  (cnt为第几次取数字)

最终答案就是dp[1][n];

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define mem(a,t) memset(a,t,sizeof(a))
#define N 2005
const int M=100005;
const int inf=0x1f1f1f1f;
int a[N],dp[N][N];
int main()
{
    int i,j,k,n;
    while(~scanf("%d",&n))
    {
        mem(dp,0);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);     //从里向外逆推区间
            dp[i][i]=a[i]*n;    //最后取的是a[i]
        }
        for(k=1;k<n;k++) //区间长度为k+1时
        {
            for(i=1;i+k<=n;i++)      //枚举区间长度为k+1的每个区间起点
            {
                j=i+k;               //该区间终点为j=i+k
                dp[i][j]=max(dp[i+1][j]+a[i]*(n-k),dp[i][j-1]+a[j]*(n-k));
            }            //该区间的最优解为先取左边或者右边两者的最大值
        }
        printf("%d\n",dp[1][n]);
    }
    return 0;
}
时间: 2024-10-21 22:26:53

poj 3186 Treats for the Cows(区间dp)的相关文章

poj 3186 Treats for the Cows (区间dp)

题意:给你一个序列,每次只能从头或为取数,然后乘以这是第几个数,最后加和,是加和最大 思路:假设长度最开始是1,然后依次枚举长度,以及起点,dp[i][j]是又里面的两端点扩出来的(ps:代码不是这么写的) 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=2007; int a[maxn],dp[maxn][maxn]; i

poj 3186 Treats for the Cows dp

#include <cstdio> #include <algorithm> using namespace std; #define maxn 2100 int dp[maxn][maxn]; int val[maxn]; int n; int main() { while(scanf("%d",&n)!=EOF) { int i,j; for(i=1;i<=n;i++) { scanf("%d",&val[i]);

POJ 3186 Treats for the Cows (简单区间DP)

FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast amounts of milk. FJ sells one treat per day and wants to maximize the money he receives over a given period time. The treats are interesting for many reasons

O - Treats for the Cows 区间DP

FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast amounts of milk. FJ sells one treat per day and wants to maximize the money he receives over a given period time. The treats are interesting for many reasons

POJ 3186 Treats for the Cows

一开始想到的是,用一个标志位记录取第i个数的时间,但后来发现这个方法不行,可能性太多,没办法推 然后就看了解题报告的思路,说是用区间dp,状态是设出来了,但受固有思维影响,老想着怎么顺着推. 最后实在想不出了,看了代码,才发现要逆着推,从结束状态开始推起,这样公式就出来了 为了保证每一层循环要用到的值都已经被计算出来了,按区间长度进行枚举 纪念第一个区间dp吧 /* dp[i][j]:剩下第i个至第j个物品时,取掉剩下的所有物品能获得的最大值 dp[i][j]=max(dp[i+1][j]+v[

POJ - 3186 Treats for the Cows (区间DP)

题目链接:http://poj.org/problem?id=3186 题意:给定一组序列,取n次,每次可以取序列最前面的数或最后面的数,第n次出来就乘n,然后求和的最大值. 题解:用dp[i][j]表示i~j区间和的最大值,然后根据这个状态可以从删前和删后转移过来,推出状态转移方程: dp[i][j]=max(dp[i+1][j]+value[i]*k,dp[i][j-1]+value[j]*k) 1 #include <iostream> 2 #include <algorithm&

POJ 3186 Treats for the Cows 一个简单DP

DP[i][j]表示现在开头是i物品,结尾是j物品的最大值,最后扫一遍dp[1][1]-dp[n][n]就可得到答案了 稍微想一下,就可以, #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<cstring> #include<vect

POJ 3042 Grazing on the Run (区间DP)

区间dp,~~~~ dp[i][j][0]表示i到j之间已经走过,并且现在在i点的staleness(可以理解为枯萎指数)最小值, dp[i][j][1]表示i到j之间已经走过,并且现在在j点的staleness最小值. 于是对于在i点,可能从i+1->i,也可能从j->i,即: 很重要的一点,在我们转移到i时,除了即将到达的i点,还有未到达的(n-(j-i+1))个点,即总共(n-(j-i))个点,它们的枯萎指数均在增加,so~ dp[i][j][0]=min(dp[i+1][j][0]+(

POJ 3186Treats for the Cows(区间DP)

题目链接:http://poj.org/problem?id=3186 题目大意:给出的一系列的数字,可以看成一个双向队列,每次只能从队首或者队尾出队,第n个出队就拿这个数乘以n,最后将和加起来,求最大和. 解题思路:有两种写法: ①这是我一开始想的,从外推到内,设立数组dp[i][j]表示剩下i~j时的最优解,则有状态转移方程: dp[i][j]=dp[i][j]=max(dp[i-1][j]+a[i-1]*(n-(j-i+1)),dp[i][j+1]+a[j+1]*(n-(j+1-i)))