DP
P3195 [HNOI2008]玩具装箱(斜率优化)
推导:
f[i]表示在取前i个玩具的情况下的最小总费用
{}
设
所以
可化为形如的式子
点击查看代码
const int N=5e4+5;
int n,m,q[N];
ll c[N],sum[N],f[N];
double slope(int j,int k)
{
return (double)(f[j]+c[j]*c[j]-f[k]-c[k]*c[k])/(double)(c[j]-c[k]);
}
int main()
{
n=read(),m=read()+1;
for(int i=1;i<=n;i++)
{
sum[i]=read()+sum[i-1];
c[i]=sum[i]+i;
}
int l=1,r=1;
for(int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1])<=2*(c[i]-m))l++;
f[i]=f[q[l]]+1ll*(c[i]-c[q[l]]-m)*(c[i]-c[q[l]]-m);
while(l<r&& slope(q[r-1],q[r])>=slope(q[r],i))r--;
q[++r]=i;
}
cout<<f[n]<<endl;
return 0;
}
P2900 [USACO08MAR]Land Acquisition G(斜率优化)
点击查看代码
double slope(int i,int j)
{
return (double)(f[i]-f[j])/double(a[j+1].len-a[i+1].len);
}
bool cmp(ww x,ww y)
{
if(x.len==y.len)return x.wid>y.wid;
return x.len>y.len;
}
int main()
{
int n;
n=read();
for(int i=1;i<=n;i++)
{
a[i].len=read(),a[i].wid=read();
}
sort(a+1,a+n+1,cmp);
int tot=1;
for(int i=1;i<=n;i++)
{
if(a[tot].wid<a[i].wid)a[++tot]=a[i];
}
int l=1,r=1;
for(int i=1;i<=tot;i++)
{
while(l<r&& slope(q[l],q[l+1])<=a[i].wid)l++;
f[i]=f[q[l]]+a[q[l]+1].len*a[i].wid;
while(l<r&& slope(q[r-1],q[r])>=slope(q[r],i) )r--;
q[++r]=i;
}
cout<<f[tot]<<endl;
return 0;
}
P3628 [APIO2010] 特别行动队(斜率优化)
点击查看代码
double slope(int j,int k)
{
return (double)(f[j]-f[k]+a*(sum[j]*sum[j]-sum[k]*sum[k])-b*(sum[j]-sum[k]))/(double)(sum[j]-sum[k]);
}
int main()
{
int n;n=read();
a=read(),b=read(),c=read();
for(int i=1;i<=n;i++)
sum[i]=read()+sum[i-1];
int l=1,r=1;
for(int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1])>=2*a*sum[i])l++;
f[i]=f[q[l]]+a*(sum[i]-sum[q[l]])*(sum[i]-sum[q[l]])+b*(sum[i]-sum[q[l]])+c;
while(l<r&& slope(q[r-1],q[r])<=slope(q[r],i))r--;
q[++r]=i;
}
cout<<f[n]<<endl;
return 0;
}
P3648 [APIO2014] 序列分割(斜率优化)
只要方案一样,不管怎么切得分都相同。
注意:因为可能与相等,这种情况要特,返回极小值;预处理初始值(即第一刀切了后的贡献)
点击查看代码
const int N=1e5+5;
ll n,k,sum[N],f[N][2];
ll fa[N][205],g[205],q[N];
double slope(int j,int i,int t)
{
if(sum[j]==sum[i])return 1e18;
return (double)(f[j][t]-f[i][t])/(double)(sum[j]-sum[i]);
}
int main()
{
n=read(),k=read();
for(int i=1;i<=n;i++)
sum[i]=read()+sum[i-1];
for(int i=1;i<=n;i++)
f[i][0]=sum[i]*(sum[n]-sum[i]);
for(int j=1;j<=k;j++)
{
int l=1,r=1,t=j%2;
for(int i=1;i<=n;i++)q[i]=0;
for(int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1],t^1)>=(sum[n]-sum[i]) )l++;
f[i][t]=f[q[l]][t^1]+(sum[n]-sum[i])*(sum[i]-sum[q[l]]);
fa[i][j]=q[l];
while(l<r&& slope(q[r-1],q[r],t^1)<=slope(q[r],i,t^1) )r--;
q[++r]=i;
}
}
cout<<f[n][k%2]<<endl;
int x=fa[n][k],tot=0;
while(x!=0&&tot<k)
{
cout<<x<<" ";tot++;
x=fa[x][k-tot];
}
cout<<endl;
retur
点击查看代码
double slope(int j,int i,int t)
{
if(sum[i]==sum[j])return -1e18;
return (double)(f[j][t]-f[i][t]-sum[j]*sum[j]+sum[i]*sum[i])/(double)(sum[i]-sum[j]);
}
int main()
{
n=read(),k=read();
for(re int i=1;i<=n;i++)
{
ll a=read();
sum[i]=a+sum[i-1];
}
for(re int j=1;j<=k;j++)
{
int l=1,r=1,t=j&1;q[1]=0;
for(re int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1],t^1)<=(double)sum[i])l++;
f[i][t]=f[q[l]][t^1]+sum[q[l]]*(sum[i]-sum[q[l]]);
fa[i][j]=q[l];
while(l<r&& slope(q[r-1],q[r],t^1)>=slope(q[r],i,t^1) )r--;
q[++r]=i;
}
}
printf("%lld\n",f[n][k&1]);
int x=fa[n][k],tot=0;
while(x!=0&&tot<k)
{
printf("%d ",x);tot++;
x=fa[x][k-tot];
}
return 0;
}
P4360 [CEOI2004] 锯木厂选址(斜率优化)
点击查看代码
double slope(int j,int k)
{
return (double)(f[j][0]+sum[j]-f[k][0]-sum[k])/(double)(w[j]-w[k]);
}
int main()
{
int n;n=read();
for(int i=1;i<=n;i++)
{
w[i]=read(),d[i]=read()+d[i-1];
sum[i]=d[i-1]*w[i]+sum[i-1];w[i]+=w[i-1];
f[i][0]=d[i-1]*w[i]-sum[i];
}
int l=1,r=1;
ll ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1])<=d[i-1])l++;
f[i][1]=f[q[l]][0]+w[i]*(d[i-1]-d[n])-w[q[l]]*d[i-1]+sum[q[l]]-sum[n]+w[n]*d[n];
ans=min(ans,f[i][1]);
while(l<r&& slope(q[r-1],q[r])>=slope(q[r],i))r--;
q[++r]=i;
}
cout<<ans<<endl;
return 0;
}
P1064 [NOIP2006 提高组] 金明的预算方案(01背包)
- 体积变为v,价格变为v*p;
- 因为只有0~2个附属品,用二维数组存在主物品后面
- 01背包模板
点击查看代码
//核心代码
for(int i=1;i<=m;i++)
{
v=read(),p=read(),q=read();
if(q==0)a[i][0]=v*p,w[i][0]=v;
if(q!=0)
{
if(a[q][1]!=0)a[q][2]=v*p,w[q][2]=v;
else a[q][1]=v*p,w[q][1]=v;
}
}
for(int i=1;i<=m;i++)
{
if(a[i][0]!=0)
{
for(int j=n;j>0;j--)
{
if(j>=w[i][0])f[j]=max(f[j],f[j-w[i][0]]+a[i][0]);
if(a[i][1]&&j>=w[i][0]+w[i][1])f[j]=max(f[j],f[j-w[i][0]-w[i][1]]+a[i][1]+a[i][0]);
if(a[i][2]&&j>=w[i][0]+w[i][2])f[j]=max(f[j],f[j-w[i][0]-w[i][2]]+a[i][2]+a[i][0]);
if(a[i][2]&&j>=w[i][0]+w[i][1]+w[i][2])f[j]=max(f[j],f[j-w[i][0]-w[i][1]-w[i][2]]+a[i][2]+a[i][1]+a[i][0]);
}
}
}
P2112 鸿雁传书
- 设计状态f[i][j],表示在把前i个单词分成j行
- 考虑三重循环,第一重枚举单词数i,第二重枚举行数j,第三重枚举从前k个单词处划开
- sum/m不一定整除,一定要开double
状态转移方程:
点击查看代码
memset(f,127,sizeof f);
f[0][0]=0;
sum/=m*1.0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=j-1;k<i;k++)
{
f[i][j]=min(f[i][j],f[k][j-1]+(len[i]-len[k]-sum)*(len[i]-len[k]-sum));
}
}
}
printf("%.1f",1.0*f[n][m]/m);
[NOI1995] 石子合并(四边形不等式优化/区间DP)
点击查看代码
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=2*n;i++)
{
int j=i+len-1;
f2[i][j]=0x3f3f3f3f;
for(int k=s[i][j-1];k<=s[i+1][j];k++)
{
if(f2[i][j]>f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1])
{
f2[i][j]=f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1];
s[i][j]=k;
}
}
f1[i][j]=max(f1[i+1][j],f1[i][j-1])+sum[j]-sum[i-1];
}
}
int ans1=0,ans2=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
ans1=max(ans1,f1[i][i+n-1]);
ans2=min(ans2,f2[i][i+n-1]);
}
cout<<ans2<<endl<<ans1<<endl;
P1912 [NOI2009] 诗人小G(四边形不等式优化)超级难!!!
点击查看代码
const int N=1e5+5;
int q[N],n,L,p,k[N],fa[N],nex[N];
ld f[N],len[N];
string s[N];
ld qow(ld x,int y)
{
ld res=1;
while(y>0)
{
if(y&1)res*=x;
x*=x;y>>=1;
}
return res;
}
ld val(int x,int y)
{
return f[x]+qow(abs(len[y]-len[x]-L-1),p);
}
int ei(int x,int y)
{
int l=x,r=n+1;
while(l<r)
{
int mid=(l+r)>>1;
if(val(x,mid)>=val(y,mid))r=mid;
else l=mid+1;
}
return l;
}
int main()
{
int t;t=read();
while(t--)
{
memset(k,0,sizeof k);
memset(fa,0,sizeof fa);
memset(nex,0,sizeof nex);
n=read(),L=read(),p=read();
for(int i=1;i<=n;i++)
{
cin>>s[i];
len[i]=s[i].length()+len[i-1]+1;
}
int l=1,r=1;q[1]=0;
for(int i=1;i<=n;i++)
{
while(l<r&& k[l]<=i)l++;
f[i]=val(q[l],i);fa[i]=q[l];
while(l<r&& k[r-1]>=ei(q[r],i))r--;
k[r]=ei(q[r],i);q[++r]=i;
}
if(f[n]>1e18)printf("Too hard to arrange\n");
else
{
printf("%lld\n",(ll)f[n]);
for(int i=n;i;i=fa[i])nex[fa[i]]=i;
for(int i=0;;i=nex[i])
{
if(nex[i]==0)break;
for(int j=i+1;j<=nex[i];j++)
{
cout<<s[j];
(j!=nex[i])?printf(" "):printf("\n");
}
}
}
puts("--------------------");
}
return 0;
}
P4072 [SDOI2016]征途(斜率优化)
注意:要先预处理最开始的值;转化数式,不使用double型函数
点击查看代码
const int N=3005;
int n,m,q[N];
ll f[N][2],a[N],sum;
double slope(int j,int k,int t)
{
return (double)(f[j][t]+a[j]*a[j]-f[k][t]-a[k]*a[k])/(double)(a[j]-a[k]);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read()+a[i-1];
sum=a[n]*a[n];
for(int i=1;i<=n;i++)f[i][0]=a[i]*a[i];
for(int j=1;j<m;j++)
{
int l=1,r=1,t=j&1;q[1]=0;
for(int i=1;i<=n;i++)
{
while(l<r&& slope(q[l],q[l+1],t^1)<=2*a[i])l++;
f[i][t]=f[q[l]][t^1]+(a[i]-a[q[l]])*(a[i]-a[q[l]]);
while(l<r&& slope(q[r-1],q[r],t^1)>=slope(q[r],i,t^1) )r--;
q[++r]=i;
}
}
cout<<f[n][m&1^1]*m-sum<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端