[NOI 2020]美食家[矩阵加速]
容易想到 dp: $f(t,x)=\max_{(v,x)\in E}f(t-w(v,x), v) + c_u$
$f(i,j)$ 表示 i 时刻在 j 点的最大收益
注意到 n,w 很小,T 有 $10^9$,考虑矩阵优化转移,设转移矩阵为 P
矩阵转移左侧是一个高度为 w*n 的向量(依次记录 $f(t,1).f(t,2),f(t,3),...,f(t,n),f(t-1,1),f(t-1,2)....$),右侧转移矩阵乘出一个向量
因为有节日的举办的存在,所以我们不能一次搞出 $P^T$,需要根据 k 个美食节把时间分成 k+1 段,每次一段乘完后在 f(t,u) 这个举办美食节的点上加上美食街的 val
因此复杂度 $O(k(5n)^3logT)$
考虑优化,我们可以预处理出来 $P^1, P^2, P^4, P^8, P^{16} ....$,然后每次一段乘的时候,可以将指数二进制拆开分别乘,因为这样是一个矩阵乘向量,所以复杂度能降低
因此复杂度 $O((5n)^3logT+(5n)^2klogT)$
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <vector> 5 #include <cstring> 6 #include <queue> 7 #include <cstdlib> 8 #define inf 100010 9 #define ll long long 10 #define INFLL 0x3f3f3f3f3f3f3f3fll 11 #define INF 0x3f3f3f3f 12 #define N 251 13 14 namespace chiaro { 15 16 template <class T> 17 inline void read(T& num) { 18 num = 0; register char c = getchar(), up = c; 19 while(!isdigit(c)) up = c, c = getchar(); 20 while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar(); 21 up == '-' ? num = - num : 0; 22 } 23 template <class T> 24 inline void read(T& a, T& b) {read(a); read(b);} 25 template <class T> 26 inline void read(T& a, T& b, T& c) {read(a); read(b); read(c);} 27 template <class T> 28 inline void read(T& a, T& b, T& c, T& d) {read(a); read(b); read(c); read(d);} 29 30 struct edge { 31 int to; 32 int val; 33 edge* nxt; 34 }; 35 36 struct ftv { 37 int t; 38 int pos; 39 int val; 40 ftv() {} 41 ftv(int t, int x, int y) { 42 this->t = t; 43 this->pos = x; 44 this->val = y; 45 } 46 }; 47 48 struct Matrix { 49 int n, m; 50 ll a[N][N]; 51 52 inline ll* operator [] (int i) { 53 return a[i]; 54 } 55 56 Matrix () {} 57 58 Matrix (int n, int m) { 59 this->n = n; 60 this->m = m; 61 for(register int i = 0; i <= n; i++) { 62 for(register int j = 0; j <= m; j++) this->a[i][j] = -INFLL; 63 } 64 } 65 66 inline void print() { 67 for(register int i = 1; i <= n; i++) { 68 for(register int j = 1; j <= m; j++) printf("%lld, ", a[i][j] == -INF ? -1 : a[i][j]); 69 puts(""); 70 } 71 } 72 }; 73 74 inline Matrix operator * (Matrix& a, Matrix& b) { 75 Matrix res(a.n, b.m); 76 for(register int i = 1; i <= a.n; i++) { 77 for(register int j = 1; j <= a.m; j++) { 78 if(a[i][j] < 0) continue; 79 for(register int k = 1; k <= b.m; k++) { 80 res[i][k] = std::max (res[i][k], a[i][j] + b[j][k]); 81 } 82 } 83 } 84 return res; 85 } 86 87 int n, m, T, k; 88 int c[inf]; 89 ftv f[N]; 90 edge* g[inf << 1]; 91 92 Matrix trans; 93 Matrix pre[31]; 94 95 inline void connect(int from, int to, int val) { 96 static edge pool[inf << 1]; 97 static edge* p = pool; 98 p->to = to; 99 p->val = val; 100 p->nxt = g[from]; 101 g[from] = p; p++; 102 return; 103 } 104 105 inline bool cmp(const ftv& a, const ftv& b) { 106 return a.t < b.t; 107 } 108 109 inline void buildTrans() { 110 trans = Matrix(n * 5, n * 5); 111 for(register int i = 1; i <= n; i++) { 112 for(auto e = g[i]; e; e = e->nxt) { 113 trans[i + (e->val - 1) * n][e->to] = c[e->to]; 114 } 115 } 116 for(register int i = 1; i <= (n << 2); i++) trans[i][i + n] = 0; 117 return; 118 } 119 120 inline void buildPre() { 121 pre[0] = trans; 122 for(register int i = 1; i < 30; i++) pre[i] = pre[i - 1] * pre[i - 1]; 123 return; 124 } 125 126 inline void gsm(Matrix& res, int k) { 127 for(register int i = 0; i < 30; i++) { 128 if(k & 1) res = res * pre[i]; 129 k >>= 1; 130 } 131 return; 132 } 133 134 inline void setting() { 135 freopen("delicacy.in", "r", stdin); 136 freopen("delicacy.out", "w", stdout); 137 return; 138 } 139 140 inline signed mian() { 141 setting(); 142 read(n, m, T, k); 143 for(register int i = 1; i <= n; i++) read(c[i]); 144 for(register int i = 1; i <= m; i++) { 145 int u, v, w; read(u, v, w); 146 connect(u, v, w); 147 } 148 for(register int i = 1; i <= k; i++) { 149 int t, x, y; read(t, x, y); 150 f[i] = ftv(t, x, y); 151 } 152 f[0] = ftv(0, 0, 0); 153 std::sort(f, f + 1 + k, cmp); 154 buildTrans(); 155 buildPre(); 156 Matrix ans(1, n * 5); ans[1][1] = 0; 157 for(register int i = 1; i <= k; i++) { 158 gsm(ans, f[i].t - f[i - 1].t); 159 if(ans[1][f[i].pos] > 0) ans[1][f[i].pos] += f[i].val; 160 } 161 if(f[k].t != T) gsm(ans, T - f[k].t); 162 if(ans[1][1] < 0) puts("-1"); 163 else printf("%lld\n", ans[1][1] + c[1]); 164 return 0; 165 } 166 167 } 168 169 signed main() { 170 return chiaro::mian(); 171 }

浙公网安备 33010602011771号