题目大意:从(0,0)走到(n,m)每次向右或者向上走一步。在第i行向右走代价是ri,列同理。求最小代价。1e5。
题解:考虑答案路径,假设当前点先向上走了x步每步代价c1,然后向右走了y步每步代价r1。考虑为啥不是先向右走了y步每步代价r2,然后向上走了x步每步代价c2。这时c1x+r1y<=c2x+r2y,化简后就是(r1-r2)/x<=(c2-c1)/y。换言之如果我们钦定先向上走x步,那么想要把先向上再向右的策略改成先右后上,就必须要找一个dalta(c)/y最小的,而这个是和x无关的,进一步地说就是c的下凸壳的下一个点。同时x为了避免被更改策略,需要做和y相同的事情。此时二者在去比较来确定是否更改策略。那么做法就是每次尝试都往凸包的下一个走,并且选择斜率较小的那一个走。随便维护一下即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define gc getchar()
#define lint long long
#define N 100010
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct P{
int x,y;P(int _x=0,int _y=0){ x=_x,y=_y; }
inline P operator=(const P &p) { return x=p.x,y=p.y,*this; }
inline P operator-(const P &p)const{ return P(x-p.x,y-p.y); }
};vector<P> r,c;
inline lint cross(const P &a,const P &b) { return (lint)a.x*b.y-(lint)a.y*b.x; }
inline lint cross(const P &s,const P &t1,const P &t2) { return cross(t1-s,t2-s); }
inline vector<P> convexHull(const vector<P> &ps)
{
int n=(int)ps.size();if(n<=2) return ps;
vector<P> ans(ps.size());int k=0;
for(int i=0;i<n;ans[k++]=ps[i++])
while(k>1&&cross(ans[k-2],ans[k-1],ps[i])<=0) k--;
return ans.resize(k),ans;
}
inline int cmp(const P &a,const P &b) { return cross(a,b)>=0; }
int main()
{
int n=inn()+1,m=inn()+1;lint ans=0ll;
r.resize(n);for(int i=0;i<n;i++) r[i]=P(i,inn());
c.resize(m);for(int i=0;i<m;i++) c[i]=P(i,inn());
r=convexHull(r),c=convexHull(c);int x=0,y=0;
while(x<(int)r.size()-1&&y<(int)c.size()-1)
{
if(cmp(r[x+1]-r[x],c[y+1]-c[y]))//<=
ans+=(lint)c[y].y*(r[x+1]-r[x]).x,x++;
else ans+=(lint)r[x].y*(c[y+1]-c[y]).x,y++;
}
if(x<(int)r.size()-1) ans+=c[c.size()-1].y*(n-1ll-r[x].x);
if(y<(int)c.size()-1) ans+=r[r.size()-1].y*(m-1ll-c[y].x);
return !printf("%lld\n",ans);
}