HDU3507(dp + 斜率优化dp)

本文介绍了一种使用斜率优化动态规划的方法,该方法适用于特定类型的最优化问题。通过一个具体的编程实例,详细展示了如何利用斜率优化减少计算复杂度,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Print Article

Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 12186 Accepted Submission(s): 3734

Problem Description
Zero has an old printer that doesn’t work well sometimes. As it is antique, he still like to use it to print articles. But it is too old to work for a long time and it will certainly wear and tear, so Zero use a cost to evaluate this degree.
One day Zero want to print an article which has N words, and each word i has a cost Ci to be printed. Also, Zero know that print k words in one line will cost

M is a const number.
Now Zero want to know the minimum cost in order to arrange the article perfectly.

Input
There are many test cases. For each test case, There are two numbers N and M in the first line (0 ≤ n ≤ 500000, 0 ≤ M ≤ 1000). Then, there are N numbers in the next 2 to N + 1 lines. Input are terminated by EOF.

Output
A single number, meaning the mininum cost to print the article.

Sample Input
5 5
5
9
5
7
5

Sample Output
230

Author
Xnozero

Source
2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT

这是我做的第一道斜率优化dp的题目,目前优化dp的方法主流有两种,一种是用单调队列优化,另外一种是用斜率优化,其实我们后来发现,斜率优化过程中也用到了单调队列,两者共同的特点,也就是优化的原理是,通过具体的问题的特点,我们可以排除一些不够优的点,而保留更优的点,这个过程我们用单调队列实现就行。由于我只做了一道题,对斜率优化的理解也不是特别深,在这里我就说这么多。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
//int inf = 1e9;
int N, M;
int sum[maxn];
int dp[maxn];
int q[maxn];
int tail, head;
int getY(int i)
{
    return (dp[i] + sum[i] * sum[i]);
}
int getX(int i)
{
    return 2 * sum[i];
}
int main()
{
    while(~scanf("%d%d", &N, &M))
    {
        int x;
        sum[0] = 0;
        for(int i = 1; i <= N; i++)
        {
            scanf("%d", &x);
            sum[i] = sum[i - 1] + x;
        }

        dp[0] = 0;
        tail = 1;
        head = 0;
        q[++head] = 0;
        for(int i = 1; i <= N; i++)
        {
            while(head - tail >= 1 && (getY(q[tail + 1]) - getY(q[tail])) <= sum[i] * (getX(q[tail + 1]) - getX(q[tail]))) tail++;
            //cout<<"tail == "<<tail<<endl;
           // printf("q[tail] == %d\n", q[tail]);
            dp[i] = dp[q[tail]] + (sum[i] - sum[q[tail]]) * (sum[i] - sum[q[tail]]) + M;
            //printf("dp[%d] == %d\n", i, dp[i]);
            if(tail >= head)
            {
                q[++head] = i;
            }
            else
            {
                while(head - tail >= 1)
                {
                    if((getY(i) - getY(q[head])) * (getX(q[head]) - getX(q[head - 1])) <= ((getY(q[head]) - getY(q[head - 1])) * (getX(i) - getX(q[head]))))
                    {
                        head--;
                    }
                    else break;
                }
                q[++head] = i;
            }

        }
        printf("%d\n", dp[N]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值