ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P7294-[USACO21JAN]Minimum Cost Paths P【单调栈】

2021-08-17 14:33:08  阅读:167  来源: 互联网

标签:Paths ll USACO21JAN sum times leq Minimum include top


正题

题目链接:https://www.luogu.com.cn/problem/P7294


题目大意

\(n\times m\)的网格,当你在\((x,y)\)时你有两种选择

  1. 花费\(x^2\)的代价向右移动
  2. 花费\(c_y\)的代价向左移动

\(q\)次询问\((1,1)\)走到\((x,y)\)的最小代价。

\(1\leq n\leq 10^9,1\leq m,q\leq 2\times 10^5\)


解题思路

假设我们开始都是直接走最上面向右的路(也就是代价都是\(1^2\))。

然后考虑在某个位置\((x,y)\)要走到\((n,m)\)时向下走会产生的贡献为\(c_y+(m-y)\times (2x+1)\)(后面要抬\(m-y\)个横着走,然后从\(x^2\)到\((x+1)^2\)要到加\(2x+1\))。

然后拆一下就是\(c_y+m-y+2xm-2xy\)。发现斜率\(-2y\)是按照\(y\)递增递减的,而且我们要求选出的若干个\(c_y\)的\(y\)一定要递增,但是这样的话我们选出来的一定是递增的所以我们只需要考虑对于每个\(x\)选择一个\(y\)使得最小化\(c_y+(m-y)\times (2x+1)\)。

按照询问排序,一个一个加入新的\(c_y\),按照斜率维护一个上凸壳,然后在凸壳上面二分就好了。

时间复杂度\(O(m+q\log m)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10;
struct node{
	ll n,m,id;
}q[N];
ll n,m,t,top,b[N],k[N],s[N],sum[N],l[N],r[N],ans[N];
ll calc(ll i,ll j)//i<j
{return (b[j]-b[i]+k[i]-k[j]-1)/(k[i]-k[j]);}
ll cap(ll i,ll j){
	ll x=calc(i,j);
	if(x<=l[i])return 1;
	return 0;
}
ll getf(ll x,ll l,ll r)
{return (r+l)*(r-l+1)/2*k[x]+b[x]*(r-l+1);}
bool cmp(node x,node y)
{return x.m<y.m;}
signed main()
{
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=m;i++){
		scanf("%lld",&b[i]);
		b[i]=b[i]-i;k[i]=2*(-i);
	}
	scanf("%lld",&t);
	for(ll i=1;i<=t;i++){
		scanf("%lld%lld",&q[i].n,&q[i].m);
		q[i].id=i;
	}
	sort(q+1,q+1+t,cmp);
	for(ll i=1,z=1;i<=m;i++){
		r[i]=n;
		while(top>0&&cap(s[top],i))top--;
		if(top)l[i]=max(calc(s[top],i),1ll);else l[i]=1;
		if(l[i]<=r[i]){
			r[s[top]]=l[i]-1;s[++top]=i;
			sum[top-1]=((top>1)?sum[top-2]:0)+getf(s[top-1],l[s[top-1]],r[s[top-1]]);
			sum[top]=sum[top-1]+getf(i,l[i],r[i]);
		}	
		while(z<=t&&q[z].m<=i){
			ll qn=q[z].n-1,L=1,R=top;
			while(L<=R){
				ll mid=(L+R)>>1;
				if(r[s[mid]]<qn)L=mid+1;
				else R=mid-1;
			}
			ans[q[z].id]=sum[L-1]+getf(s[L],l[s[L]],qn)+(qn+1)*qn*i+i*qn+i-1;
			z++;
		}
	}
	for(ll i=1;i<=t;i++)
		printf("%lld\n",ans[i]);
	return 0;
}

标签:Paths,ll,USACO21JAN,sum,times,leq,Minimum,include,top
来源: https://www.cnblogs.com/QuantAsk/p/15152175.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有