[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 }

 

posted @ 2020-08-24 14:03  Chiaro  阅读(302)  评论(0)    收藏  举报