1. 程式人生 > 其它 >HDU3507 Print Article

HDU3507 Print Article

技術標籤:單調佇列

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.

思路

這道題使用斜率優化,設dp[i]為前i個的最優值,那麼顯然有:
d p i = m i n ( d p j + s q r ( s i − s j ) + m ) ( 1 < = j < i ) dp_i=min(dp_j+sqr(s_i-s_j)+m)(1<=j<i) dpi=min(dpj+sqr(sisj)+m)(1<=j<i)
s i s_i si為字首和,然後我們考慮斜率優化。


我們首先假設在算 dp[i]時,k<j ,j點比k點優。

也就是 d p [ j ] + ( s u m [ i ] − s u m [ j ] ) 2 + M < = d p [ k ] + ( s u m [ i ] − s u m [ k ] ) 2 + M dp[j]+(sum[i]-sum[j])^2+M <= dp[k]+(sum[i]-sum[k])^2+M dp[j]+(sum[i]sum[j])2+M<=dp[k]+(sum[i]sum[k])2+M;
對上述方程進行整理移項很容易得到:(初一數學
[ ( d p [ j ] + s u m [ j ] ∗ s u m [ j ] ) − ( d p [ k ] + s u m [ k ] ∗ s u m [ k ] ) ] / 2 ( s u m [ j ] − s u m [ k ] ) < = s u m [ i ] [(dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k])] / 2(sum[j]-sum[k]) <=sum[i] [(dp[j]+sum[j]sum[j])(dp[k]+sum[k]sum[k])]/2(sum[j]sum[k])<=sum[i].
注意整理中要考慮下正負,涉及到不等號的方向。
左邊我們令: y j = d p [ j ] + s u m [ j ] ∗ s u m [ j ] , x j = 2 ∗ s u m [ j ] y_j=dp[j]+sum[j]*sum[j] , x_j=2*sum[j] yj=dp[j]+sum[j]sum[j],xj=2sum[j]
那麼就變成了斜率表示式: ( y j − y k ) / ( x j − x k ) < = s u m [ i ] (y_j-y_k)/(x_j-x_k) <= sum[i] yjyk/(xjxk)<=sum[i];(初中數學??
而且不等式右邊是遞增的。


所以我們可以看出以下兩點:我們令 g [ k , j ] = ( y j − y k ) / ( x j − x k ) g[k,j]=(y_j-y_k)/(x_j-x_k) g[k,j]=(yjyk)/(xjxk)
第一:如果上面的不等式成立,那就說j比k優,而且隨著i的增大上述不等式一定是成立的,也就是對i以後算DP值時,j都比k優。那麼k就是可以淘汰的。(滿足單獨佇列特性)(單調佇列前面的出隊方法)

第二:如果 k<j<i 而且 g[k,j]>g[j,i] 那麼 j 是可以淘汰的。
如果 g[j,i]<=sum[i]就是i比j優,那麼j沒有存在的價值
如果 g[j,i]>sum[i] 那麼同樣有 g[k,j]>sum[i] 那麼 k比 j優 那麼 j 是可以淘汰的(單調佇列的末尾出隊判斷)


在程式碼實現中我們不需要用g[k,j],我們可以使用函式來代表 x i , y j x_i,y_j xi,yj和dp方程.
code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<cstdio>
#include<map>
using namespace std;
int f[500001],s[500001],a[500001];
int mx,t,v,w,c,b,k,x,l,r;
int n,p,q,i,m;
void read(int& x)
{
	x=0;
	int f=1;
	char ch=getchar();
	while (!isdigit(ch)) (ch=='-')&&(f=-1),ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	x*=f;
}
void wr(int x)
{
	(x<0)&&(x=-x,putchar('-'));
	if (x>9) wr(x/10);
	putchar(x%10^48);
}
int dp1(int x,int y)
{
	return f[x]+m+(s[x]-s[y])*(s[x]-s[y]);
}
int f1(int x,int y)
{
	return f[x]+s[x]*s[x]-f[y]-s[y]*s[y];
}
int f2(int x,int y)
{
	return (s[x]-s[y]);
}
int main()
{
	while (cin>>n>>m)//**讀入
	{
		s[0]=0;
		for (i=1;i<=n;i++)
		{
			cin>>x;
			s[i]=s[i-1]+x;
			f[i]=0;
		}
		f[0]=0;
		l=0,r=0;
		for (int i=1;i<=n;i++)
		{
			while (l<r&&f1(a[l+1],a[l])<=2*s[i]*f2(a[l+1],a[l])) l++;
			f[i]=dp1(a[l],i);
			while (l<r&&f1(i,a[r])*f2(a[r],a[r-1])<=f1(a[r],a[r-1])*f2(i,a[r]))
			{
				r--;
			}
			a[++r]=i;
		}
		wr(f[n]);
		printf("\n");
	}
	return 0;
}