EOJ440 Buying Feed

EOJ440 Buying Feed

Time Limit: 2000MS   Memory Limit: 65536K
Total Submits: 135   Accepted: 16
 

Description

Farmer John needs to travel to town to pick up K (1 <= K <= 10,000) pounds of feed. Driving a mile with K pounds of feed costs FJ K*K cents; driving D miles with K pounds of feed in his truck costs FJ D*K*K cents. 

FJ can purchase feed from any of N (1 <= N <= 500) stores (conveniently numbered 1..N) that sell feed. Each store is located on a segment of the X axis whose length is E (1 <= E <= 500) miles. Store i is at location X_i (0 < X_i < E) on the number line and can sell FJ as much as F_i (1 <= F_i <= 10,000) pounds of feed at a cost of C_i (1 <= C_i <= 10,000,000) cents per pound. Surprisingly, a given point on the X axis might have more than one store. 

FJ starts driving at location 0 on this number line and can drive only in the positive direction, ultimately arriving at location E with at least K pounds of feed. He can stop at any of the feed stores along the way and buy any amount of feed up to the the store's limit. 

What is the minimum amount FJ must pay to buy and transport the K pounds of feed? FJ knows he can purchase enough feed. 

Consider this example where FJ needs two pounds of feed which he must purchase from some of the three stores at locations 1, 3, and 4 on a number line whose range is 0..5: 
      0   1   2   3   4   5  X
+---|---+---|---|---+
1 1 1 Available pounds of feed
1 2 2 Cents per pound

It is most economical for FJ to buy one pound of feed from both the second and third stores. He must pay two cents to buy each pound of feed for a total cost of 4. FJ's driving from location 0 to location 3 costs nothing, since he is carrying no feed. When FJ travels from 3 to 4 he moves 1 mile with 1 pound of feed, so he must pay 1*1*1 = 1 cents. 

When FJ travels from 4 to 5 he moves one mile with 2 pounds of feed, so he must pay 1*2*2 = 4 cents. 

His feed cost is 2 + 2 cents; his travel cost is 1 + 4 cents. The total cost is 2 + 2 + 1 + 4 = 9 cents. 

Input

* Line 1: Three space-separated integers: K, E, and N 

* Lines 2..N+1: Line i+1 contains three space-separated integers: X_i, F_i, and C_i 

Output

* Line 1: A single integer that is the minimum cost for FJ to buy and transport the feed

Sample Input

2 5 3 
3 1 2 
4 1 2 
1 1 1 

Sample Output

9
********************************************************
题目大意:一条直线上坐落着n个商店,一个人从0出发到e点,他到e点时必须买齐k件物品。他的花费有两个方面:1、在商店买物品,每个商店物品的单价不尽相同,每个商店提供的物品数量有上限;2、他背着i件物品走过L米要交路费L*i*i的数量。问最后的时候,求他的花费最小。
解题思路:dp+单调队列优化。
话说单调队列优化的dp写过,但没这么正规地写过。
状态转移方程:dp[h][j]表示到达h这个商品,身上有了j件物品所需的最小花费;
dp[h][j]=min{dp[h-1][i]+L*i*i+C*(j-i)},1<=i<j
淳朴地状态转移需要n^2的复杂度。借助单调队列优化:
令S[k]表示当i取成k时候的值:
取k1<k2,
S[k1]-S[k2]=dp[h-1][k1]-dp[h-1][k2]+L*(k1*k1-k2*k2)-C*(k1-k2)
令S[k1]-S[k2]<0
dp[h-1][k1]-dp[h-1][k2]+L*(k1*k1-k2*k2)-C*(k1-k2)<0;
因为实际的时候,k2=k1+1
所以,当dp[h-1][k]-dp[h-1][k+1]-L*(2*k1+1)+C<0的时候有最优解。
于是可以用单调队列优化。
下面引用论文原文:

单调队列的优化的主要思路:能优化的就是状态转移的j,(动态规划主要的优化思路)那么对于j来说,我们必须要构造一个 j1与j2之间的关系,这个关系必须保证 j1<j2,也就是j在单调递增时,那个关系也必须单调(像本题中的g的关系),并且j与当前的状态i没有直接的关系。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define N 10005
#define M 505
using namespace std;

struct Node
{
    long long x,f,c,tx;
    bool operator<(const Node & a)const
    {
        return x<a.x;
    }
}node[M];
long long k,e,n;
long long dp[M][N];

void re(void)
{
    scanf("%I64d%I64d%I64d",&k,&e,&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d%I64d%I64d",&node[i].x,&node[i].f,&node[i].c);
}

void run(void)
{
    sort(node+1,node+1+n);
    memset(dp,-1,sizeof(dp));
    for(int i=2;i<=n;i++)
        node[i].tx=node[i].x-node[i-1].x;
    for(int i=0;i<=k&&i<=node[1].f;i++)
        dp[1][i]=node[1].c*i;
    for(int i=2;i<=n;i++)
    {
        dp[i][0]=0;
        int top=0,ed=0;
        for(int j=1;j<=k;j++)
        {
            ed++;
            for(;top<=ed-1;top++)
            {
                if(dp[i-1][top+1]==-1)break;
                if(j-top>node[i].f)continue;
                int a=dp[i-1][top+1]-dp[i-1][top]+node[i].tx*(2*top+1)-node[i].c;
                if(a>0)break;
            }
            if(j-top>node[i].f)break;
            dp[i][j]=dp[i-1][top]+node[i].tx*top*top+node[i].c*(j-top);
        }
    }
    long long ans=dp[n][k];
    ans+=k*k*(e-node[n].x);
    printf("%I64d\n",ans);
}

int main()
{
    re();
    run();
    return 0;
}

  

也许有挫折,但这些,怎能挡住湘北前进的步伐
原文地址:https://www.cnblogs.com/Fatedayt/p/2240227.html