DP

P3195 [HNOI2008]玩具装箱(斜率优化)

推导:
f[i]表示在取前i个玩具的情况下的最小总费用
f[i]=min{f[j]+(sumc[i]+ijsumc[j]1l)2}
f[i]=f[j]+(sumc[i]+i(sumc[j]+j+1+l))2
a[i]=sumc[i]+i,b[i]=sumc[j]+j+1+l
所以f[i]=f[j]+(a[i]b[j])2
f[i]=f[j]+a[i]22a[i]b[j]+b[j]2
f[j]+b[j]2=f[i]+2a[i]b[i]a[i]2
可化为形如ax+b=y的式子

点击查看代码
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] 序列分割(斜率优化)

只要方案一样,不管怎么切得分都相同。

注意:因为sumj可能与sumk相等,这种情况要特,返回极小值;预处理初始值(即第一刀切了后的贡献)

点击查看代码
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背包)

  1. 体积变为v,价格变为v*p;
  2. 因为只有0~2个附属品,用二维数组存在主物品后面
  3. 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 鸿雁传书

  1. 设计状态f[i][j],表示在把前i个单词分成j行
  2. 考虑三重循环,第一重枚举单词数i,第二重枚举行数j,第三重枚举从前k个单词处划开
  3. sum/m不一定整除,一定要开double
    状态转移方程:

f[i][j]=min(f[i][j],j1k<if[k][j1]+(lenilenksum)2)

点击查看代码
	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;
} 

P4767 [IOI2000]邮局(四边形不等式优化/区间DP)

posted @   两只风小鱼  阅读(216)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起