城市交通
jzoj 1749
题目大意
有n个点,x到y的前提是x<y,代价是(y−x)∗ax+by(y-x)*a_x+b_y(y−x)∗ax+by,问从1到n的最小代价是多少
输入样例
4
2 9 5 4
9 1 2 2
输出样例
8
数据范围
对于20%的数据,1⩽n⩽100;1\leqslant n\leqslant 100;1⩽n⩽100;
对于50%的数据,1⩽n⩽3000;1\leqslant n\leqslant 3000;1⩽n⩽3000;
对于100%的数据,1⩽n⩽100000,1⩽Ai,Bi⩽109。1\leqslant n\leqslant 100000,1\leqslant Ai,Bi\leqslant 10^9。1⩽n⩽100000,1⩽Ai,Bi⩽109。
解题思路
y要大于x,就说明不能倒着走,那就可以用DP来做
我们设fif_ifi为到从1到i的最小代价,如果我们直接枚举从哪里来,那时间复杂度就是o(n2)o(n^2)o(n2),那就会TLE
那我们考虑优化
我们可以用单调队列来存有用的状态
有用的状态(i)对比前面所有有用的状态(j)都必须满足以下两个条件之一
1:、ai<aja_i<a_jai<aj
2、bi<bjb_i<b_jbi<bj
这样才可能使答案更优
后面的状态只须从有用的状态转移
当然这样还是可能被卡,但数据太水,A了
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll n, w, p, a[100500], b[100500], f[100500], k[100500];
int main()
{scanf("%lld", &n);for (ll i = 1; i <= n; ++i)scanf("%lld", &a[i]);for (ll i = 1; i <= n; ++i)scanf("%lld", &b[i]);memset(f, 127/3, sizeof(f));f[1] = 0;k[++w] = 1;//有用的状态for (ll i = 2; i <= n; ++i){p = 1;for (int j = 1; j <= w; ++j){f[i] = min(f[i], f[k[j]] + a[k[j]] * (i - k[j]) + b[i]);//转移if (a[i] > a[k[j]] && b[i] > b[k[j]]) p = 0;//判断是否是有用的状态}if (p)k[++w] = i;//加入}printf("%lld", f[n]);return 0;
}
注:
这道题还可以用斜率优化做,但本蒟蒻还要学习学习