[BZOJ 1010]
显然,用dp[i]表示前i个玩具所需最小费用,则有
dp[i]=min{dp[j]+cost(i,j+1)}
cost(i,j)表示i~j的玩具塞入一个容器的代价
即设有j>k且dp[j]+cost(i,j+1)<dp[k]+cost(i,k+1)
解得当(dp[j]-dp[k]+(j+c[j])^2-(k+c[k])^2)/((j+c[j]-k-c[k])*2)<i-1+c[i]-L时j比k优
即代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 50000 +100
#define pf(x) ((x)*(x))
using namespace std;
typedef long long ll;
ll dp[maxn],L,que[maxn],c[maxn];
int n,l,r;
double calc(int j,int k){
return (double)(dp[j]-dp[k]+pf(j+c[j])-pf(k+c[k]))/
2/(double)(j+c[j]-k-c[k]);
}
int main(){
scanf("%d%d",&n,&L);
for(int i=1;i<=n;++i)
scanf("%lld",&c[i]),c[i]+=c[i-1];
for(int i=1;i<=n;++i){
while(l<r&&calc(que[l+1],que[l])<i-1+c[i]-L)l++;
int t=que[l];
dp[i]=dp[t]+pf(i-t-1+c[i]-c[t]-L);
while(l<r&&calc(i,que[r])<calc(que[r],que[r-1]))r--;
que[++r]=i;
}
printf("%lld",dp[n]);
}
[BZOJ 2351]
用dp[i]表示1~i的村庄到B地花费的最小代价
则有dp[i]=min{dp[j]+A(在j+1修站时j+1~i的村民到B地的最小代价)}
A即是这些村民原本到b的代价-村民个数*站到B地距离.
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 40100
typedef long long ll;
struct data{
ll t,r;
data(){}
data(int t):r(0),t(t){}
bool operator<(const data& d)const{
return t<d.t;
}
bool operator==(const data& d)const{
return t==d.t;
}
void scan(){
scanf("%lld%lld",&t,&r);
}
};
ll dp[maxn];
int n,m,q[maxn],l,r;
data d[maxn],s[maxn];
double calc(int j,int k){
return (double)(dp[j]-dp[k]+s[k].t-s[j].t+1.0*d[j+1].t*d[j].r-1.0*d[k].r*d[k+1].t)/(double)(d[j+1].t-d[k+1].t);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)d[i].scan();
sort(d+1,d+n+1);
for(int i=1;i<=n;++i)s[i].t=d[i].t*d[i].r;
for(int i=1;i<=n;++i)s[i].t+=s[i-1].t;
for(int i=1;i<=n;++i)d[i].r+=d[i-1].r;
q[l=r=1]=0;
for(int i=1;i<=n;++i){
dp[i]=s[i].t-s[0].t;
while(l<r&&calc(q[l+1],q[l])<d[i].r)l++;
int x=q[l];
dp[i]=min(dp[i],dp[x]+s[i].t-s[x].t-d[x+1].t*(d[i].r-d[x].r)+m);
while(l<r&&calc(i,q[r])<calc(q[r],q[r-1]))r--;
q[++r]=i;
}
printf("%lld\n",dp[n]);
}
注意:不要恶(ao)意(miao)去(chong)重,数据是
精心设计的
[BZOJ 3675]
懒得解释了,解一下不等式即可
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[101000][2],s[101000];
int que[101000],n,k,l,r,f=0;
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%lld",&s[i]),s[i]+=s[i-1];
for(int i=1;i<=k;++i,f=!f){
que[l=r=0]=i-1;
for(int j=i;j<=n;++j){
while(l<r&&dp[que[l]][!f]-dp[que[l+1]][!f]<=(s[n]-s[j])*(s[que[l]]-s[que[l+1]]))l++;
// printf("[%I64d]",s[n]-s[j]);
dp[j][f]=max(dp[j][f],dp[que[l]][!f]+(s[n]-s[j])*(s[j]-s[que[l]]));
// printf("dp[%d][%d] cho=%d +%I64d*%I64d =>%I64d\n",j,f,que[l],(s[n]-s[j]),(s[j]-s[que[l]]),dp[j][f]);
while(l<r&&(dp[j][!f]-dp[que[r]][!f])*(s[que[r]]-s[que[r-1]])>=
(dp[que[r]][!f]-dp[que[r-1]][!f])*(s[j]-s[que[r]]))r--;
que[++r]=j;
}
}
ll ans=0;
for(int i=k;i<=n;++i)ans=max(ans,dp[i][!f]);
printf("%lld",ans);
}
[BZOJ 1911]
懒得解释了 Water~~~
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 1000000 + 100
using namespace std;
typedef long long ll;
ll dp[maxn],s[maxn];
int n,a,b,c,sol[maxn],que[maxn],l=1,r=1;
void readint(int &x){
char act=0;
while(!isdigit(act=getchar()));
x=act-'0';
while(isdigit(act=getchar()))x=(x<<3)+(x<<1)+act-'0';
}
double inline calc(int j,int k){
return (double)(a*(s[j]*s[j]-s[k]*s[k])+dp[j]-dp[k]+b*(s[k]-s[j]))/(double)(2*a*(s[j]-s[k]));
}
ll inline gdp(int i,int j){
ll x=s[i]-s[j];
return a*x*x+b*x+c;
}
int main(){
scanf("%d%d%d%d",&n,&a,&b,&c);
for(int i=1;i<=n;++i)readint(sol[i]);
for(int i=1;i<=n;++i)s[i]=s[i-1]+sol[i];
for(int i=1;i<=n;++i){
while(l<r&&calc(que[l+1],que[l])<s[i])l++;
dp[i]=gdp(i,que[l])+dp[que[l]];
while(l<r&&calc(que[r],i)<calc(que[r],que[r-1]))r--;
que[++r]=i;
}
printf("%lld",dp[n]);
}