P10769 「CROI · R2」公交接驳 题解
Iris_Aurora · · 题解
数轴上有
n 个节点1\sim n ,每个节点有权值v_i ,第i 个节点和第i+1 个节点的距离为s_i 。要求在数轴上安排
k 条路线,指定它的起点和出发时刻(出发时刻可以是负数),它会依次经过编号\ge 起点的所有点,到达节点i 的时刻为出发时刻加上起点和节点i 之间的距离,要求安排路线后,满足第
i 个节点在\ge t_i 的时刻有路线经过,设在\ge t_i 的时刻中最早经过i 的路线到达节点i 的时刻为T_i ,该路线的起点权值为V_i (若多条路线同时到达取最小),则答案为ans=\sum_{i=1}^n(T_i-t_i)\times V_i ,你需要最小化这个值。你需要处理
p 组t 数组不同的询问,且对于每个t 数组,询问 对于q_i 个k_i 的答案。
首先因为
我们假设
为了方便表述,我们令
首先有朴素 dp,令
我们枚举上一个贡献区间的终点
然后因为
显然左式比右式增速慢,于是左式永远优于右式,所以随着
所以我们以
时间复杂度
#include<bits/stdc++.h>
#define FL(i,a,b) for(ll i=(a);i<=(b);i++)
#define FR(i,a,b) for(ll i=(a);i>=(b);i--)
#define ll long long
#define ull unsigned long long
#define ld long double
#define PII pair<ll,ll>
using namespace std;
const ll MAXN = 1e3 + 10;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n,q;
ll s[MAXN],v[MAXN];
ll t[MAXN],pre[MAXN];
ll val[MAXN][MAXN];
ll f[MAXN],g[MAXN],pos[MAXN];
ll ans[MAXN];
void solve(ll l,ll r,ll L,ll R){
if(l>r) return ;
if(L==R){
FL(i,l,r) g[i]=f[L]+val[L+1][i];
return ;
}
ll mid=(l+r)>>1;
FL(i,max(pos[mid],L),min(mid-1,R))
if(f[i]+val[i+1][mid]<g[mid])
g[mid]=f[i]+val[i+1][mid],pos[mid]=i;
solve(l,mid-1,L,pos[mid]);
solve(mid+1,r,pos[mid],R);
}
signed main(){
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
scanf("%lld",&n);
FL(i,1,n-1) scanf("%lld",&s[i]);
FL(i,1,n) scanf("%lld",&v[i]);
FL(i,2,n) v[i]=min(v[i],v[i-1]);
ll Num;
scanf("%lld",&Num);
while(Num--){
FL(i,1,n) scanf("%lld",&t[i]);
FL(i,1,n-1) pre[i]=pre[i-1]+(s[i]-(t[i+1]-t[i]));
FL(i,1,n)
FL(j,i+1,n)
val[i][j]=val[i][j-1]+v[i]*(pre[j-1]-pre[i-1]);
FL(i,0,n) f[i]=g[i]=inf,pos[i]=0;
f[0]=0;
FL(k,1,n){
solve(1,n,0,n-1);
FL(j,1,n) f[j]=g[j],g[j]=inf;
ans[k]=f[n];
}
scanf("%lld",&q);
while(q--){
ll k;
scanf("%lld",&k);
printf("%lld ",ans[min(n,k)]);
}
puts("");
}
}