BZOJ3437 小P的牧场
Description
背景
小P是个特么喜欢玩MC的孩纸。。。
描述
小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第i个牧场建立控制站的花费是ai,每个牧场i的放养量是bi,理所当然,小P需要总花费最小,但是小P的智商有点不够用了,所以这个最小总花费就由你来算出啦。Input
第一行一个整数 n 表示牧场数目 第二行包括n个整数,第i个整数表示ai 第三行包括n个整数,第i个整数表示bi
Output
只有一行,包括一个整数,表示最小花费
Sample Input
4
2 4 2 4
3 1 4 2Sample Output
9
Hint
样例解释 选取牧场1,3,4建立控制站,最小费用为2+(2+1*1)+4=9。
数据范围与约定 对于100%的数据,1<=n<=1000000
BZOJ1010[HNOI2008] 玩具装箱toy
Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1…N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.
Input
第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
Output
输出最小费用
Sample Input
5 4
3
4
2
1
4Sample Output
Solution:
两道斜率优化题,算是比较经典吧。
#include<stdio.h>
#include<iostream>
#define ll long long
#define M 1000005
using namespace std;
ll sum[M],K[M],dp[M],A[M],B[M],Q[M];
double g(int k,int j){
return 1.0*(dp[k]-sum[k]+1LL*k*K[k]-dp[j]+sum[j]-1LL*j*K[j])/(K[k]-K[j]);
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>A[i];
for(int i=1;i<=n;i++){
cin>>B[i];
K[i]=K[i-1]+B[i];
}
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+K[i-1];
dp[0]=0;
int L=0,R=-1;
Q[++R]=0;
for(int i=1;i<=n;i++){
while(L<R&&g(Q[L+1],Q[L])<=i)L++;
int id=Q[L];
dp[i]=dp[id]+A[i]+sum[i]-sum[id]-1LL*(i-id)*K[id];
while(L<R&&g(i,Q[R])<=g(Q[R],Q[R-1]))R--;
Q[++R]=i;
}
cout<<dp[n]<<endl;
return 0;
}
#include<stdio.h>
#include<iostream>
#define ll long long
#define M 50005
using namespace std;
int A[M],Q[M],d;
ll C[M],dp[M],sum[M];
ll sqr(ll x){
return x*x;
}
double g(int i,int j){
return 1.0*(dp[i]-dp[j]+sqr(d+C[i])-sqr(d+C[j]))/(2ll*(C[i]-C[j]));
}
int main(){
int n,l;
scanf("%d %d",&n,&l);
d=l+1;
for(int i=1;i<=n;i++)
scanf("%d",&A[i]);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+A[i];
C[i]=sum[i]+i;
}
int L=0,R=-1;
Q[++R]=0;
for(int i=1;i<=n;i++){
while(L<R&&g(Q[L+1],Q[L])<=C[i])L++;
int id=Q[L];
dp[i]=dp[id]+sqr(C[i]-C[id]-d);
while(L<R&&g(Q[R-1],Q[R])>g(Q[R],i))R--;
Q[++R]=i;
}
cout<<dp[n]<<endl;
return 0;
}
玩具装箱这题数据貌似挺水的,下面这个加了一点决策单调性的小优化的代码也能过…
#include<stdio.h>
#include<string.h>
#include<iostream>
#define M 50005
#define ll long long
using namespace std;
int A[M],K[M];
ll sum[M],dp[M];
bool check(ll &a,ll b){
if(a==-1||a>b){a=b;return true;};
return false;
}
int main(){
int n,l,top=0;
scanf("%d %d",&n,&l);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
sum[i]=sum[i-1]+A[i];
}
memset(dp,-1,sizeof(dp));
dp[0]=0;
K[0]=1;
for(int i=1;i<=n;i++){
for(int j=K[i-1];j<=i;j++)
if(check(dp[i],dp[j-1]+(sum[i]-sum[j-1]+i-j-l)*(sum[i]-sum[j-1]+i-j-l)))K[i]=j;
}
cout<<dp[n]<<endl;
return 0;
}