好抽象的题目,提供一个看似正常一点的思路?
考虑调整法,假设我们从 \((i,j)\) 走到 \((k,l)\),那么有两种走法:
- 先向右走,\((i,j)\rightarrow (i,l)\rightarrow (k,l)\),贡献为 \(a_i\times (l-j)+b_l\times (k-i)\)。
- 先向下走,\((i,j)\rightarrow (k,j)\rightarrow (k,l)\),贡献为 \(b_j\times (k-i)+a_k\times (l-j)\)。
假设先向右走更优(向下同理),则需要满足:
\[\frac{a_k-a_i}{k-i}\gt \frac{b_l-b_i}{l-i}
\]
那么最优路径的每一个拐点一定都满足单调递增。
如果存在 \(i \lt j\lt k,\frac{a_j-a_i}{j-i}\lt\frac{a_k-a_j}{k-j}\),如果我们走完 \(i\rightarrow k\) 而是分开走,那么最优路径不可能同时满足他们与中间的竖向边的关系。所以我们只保留斜率递增的凸包即可。
保留凸包后,我们每一次只能走斜率更小的一边,否则以后一定无法满足上述限制,综上,贪心即可。
#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define int long long
#define ll long long
int n,m;ll ans=0;
int a[N],b[N],qa[N],ra,qb[N],rb;
void solve(int a[],int n,int q[],int &r){
q[++r]=1;q[++r]=2;
for(int i=3;i<=n;i++){
while(r>=2&&1ll*(a[q[r]]-a[q[r-1]])*(i-q[r])>1ll*(a[i]-a[q[r]])*(q[r]-q[r-1]))--r;
q[++r]=i;
}
q[r+1]=q[r];
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=m;i++)scanf("%lld",&b[i]);
solve(a,n,qa,ra);solve(b,m,qb,rb);
int x=1,y=1;
while(x<ra||y<rb){
if(y==rb||1ll*(a[qa[x+1]]-a[qa[x]])*(qb[y+1]-qb[y])<1ll*(b[qb[y+1]]-b[qb[y]])*(qa[x+1]-qa[x]))ans+=1ll*(qa[x+1]-qa[x])*b[qb[y]],++x;
else ans+=1ll*(qb[y+1]-qb[y])*a[qa[x]],++y;
}
printf("%lld\n",ans);
}