这道题目是不太好想的,尽管很容易看出来应该是dp,但是状态转移总觉得无从下手。
其实我们可以将状态分层,比如设$dp(i, j)$为用$i$个路由器覆盖前$j$个点所需的最小代价
我们先不考虑状态,而是考虑在每个位置上的决策对状态的影响,考虑在位置j的决策
1.如果在此处放置网线,有$dp(i, j) = min(dp(i, j), dp(i, j - 1) + b(i))$
2.如果在此处放置路由器,有$dp(i, r(j)) = min(dp(i, r(j)), dp(i - 1, l(j) - 1) + a(i))$
当然此处可以什么都不放,但是这种决策对状态没有影响,因此我们不考虑它。
$[l(i), r(i)]$表示$i$位置路由器的覆盖区间
注意到固定$i$,$dp(i, j)$应该是非降的,因此条件2的更新应该适用于所有$dp(i, k): k leq r(j)$
用两重循环依次计算状态,用stl中的vector储存i位置满足$r(k) = i$的所有$k$,先用式2从后往前更新,再用式1从前往后更新即可
复杂度$O(n * max(k, log(n))$
代码如下:
1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <queue> 6 #include <map> 7 #include <set> 8 #include <ctime> 9 #include <iostream> 10 using namespace std; 11 typedef long long ll; 12 const int int_inf = 0x3f3f3f3f; 13 const ll ll_inf = (ll)1 << 62; 14 const int mod = 1e9 + 7; 15 const double double_inf = 1e30; 16 typedef unsigned long long ul; 17 #define max(a, b) ((a) > (b) ? (a) : (b)) 18 #define min(a, b) ((a) < (b) ? (a) : (b)) 19 #define mp make_pair 20 #define st first 21 #define nd second 22 #define lson (u << 1) 23 #define rson (u << 1 | 1) 24 #define pii pair<int, int> 25 #define pb push_back 26 #define type(x) __typeof(x.begin()) 27 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++) 28 #define FOR(i, s, t) for(int i = s; i <= t; i++) 29 #define ROF(i, t, s) for(int i = t; i >= s; i--) 30 #define dbg(x) cout << x << endl 31 #define dbg2(x, y) cout << x << " " << y << endl 32 #define clr(x, i) memset(x, (i), sizeof(x)) 33 #define maximize(x, y) x = max((x), (y)) 34 #define minimize(x, y) x = min((x), (y)) 35 inline int readint(){ 36 bool neg = 0; char ch, t[11]; 37 int k = 0; 38 while((ch = getchar()) == ' ' || ch == ' ') ; 39 neg = ch == '-'; 40 ch == '-' ? neg = 1 : t[k++] = ch; 41 while((ch = getchar()) >= '0' && ch <= '9') t[k++] = ch; 42 int x = 0, y = 1; 43 while(k) x += (t[--k] - '0') * y, y *= 10; 44 return neg ? -x : x; 45 } 46 47 inline int readstr(char *s){ 48 char ch; 49 int len = 0; 50 while((ch = getchar()) == ' ' || ch == ' ') ; 51 *(s++) = ch, ++len; 52 while((ch = getchar()) != ' ' && ch != ' ') *(s++) = ch, ++len; 53 *s = '