NOIP 2014飞扬的小鸟(DP优化)
题目链接 飞扬的小鸟
考场的70分暴力(实际只有50分因为数组开小了……)
考场代码(数组大小已修改)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <functional> 6 7 using namespace std; 8 9 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 10 #define dec(i, a, b) for (int i(a); i >= (b); --i) 11 #define LL long long 12 #define fi first 13 #define se second 14 15 16 const int INF = 1 << 30; 17 const int N = 10000 + 10; 18 const int M = 1000 + 10; 19 20 int dp[M][N], x[N], y[N], u[N], d[N]; 21 int n, m, q, ans, xn, ln, rn, _max, pos; 22 bool c[N]; 23 24 int main(){ 25 26 scanf("%d %d %d ", &n, &m, &q); 27 rep(i, 0, n - 1) scanf("%d %d ", x + i, y + i); 28 rep(i, 0, n) u[i] = m, d[i] = 1; 29 memset(c, false, sizeof c); 30 rep(i, 1, q){ 31 scanf("%d %d %d ", &xn, &ln, &rn); 32 c[xn] = true; 33 u[xn] = rn - 1; 34 d[xn] = ln + 1; 35 } 36 //rep(i, 0, n) printf("%d %d\n", d[i], u[i]); 37 memset(dp, 0xff70, sizeof dp);_max = dp[1][1]; 38 rep(i, 0, m) dp[0][i] = 0; 39 rep(i, 0, n - 1){ 40 rep(j, d[i], u[i]){ 41 if (dp[i][j] >= _max) continue; 42 int k = j - y[i]; 43 if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j]); 44 k = j;int num = 0; 45 while (true){ 46 k += x[i]; ++num; 47 if (k > m) k = m; 48 if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j] + num); 49 if (k == m) break; 50 } 51 } 52 } 53 54 ans = _max; 55 rep(i, 1, m) ans = min(ans, dp[n][i]); 56 if (ans < _max){ 57 printf("%d\n%d\n", 1, ans);return 0; 58 } 59 60 bool flag = false; 61 ans = 0; 62 dec(i, n, 0) {rep(j, 0, m) if (dp[i][j] < _max) { pos = i - 1;flag = true; break;} if (flag) break;} 63 dec(i, pos, 0) if (c[i]) ++ans; 64 printf("%d\n%d\n", 0, ans); 65 66 67 68 return 0; 69 }
然后回过来想正解。
其实我们把很多时间都浪费在这里了:
1 while (true){ 2 k += x[i]; ++num; 3 if (k > m) k = m; 4 if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j] + num); 5 if (k == m) break; 6 }
其实这一步可以转过来直接利用完全背包的性质优化一下。转移只要O(1)就可以了。
这道题细节还是很多的,比较容易写挂。
正解:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 const int INF = 1 << 29; 9 const int N = 10000 + 10; 10 const int M = 1000 + 10; 11 12 int dp[N][M], x[N], y[N], u[N], d[N]; 13 int n, m, q, ans, xn, ln, rn, _max, pos; 14 bool c[N]; 15 16 int main(){ 17 18 scanf("%d %d %d ", &n, &m, &q); 19 u[n] = m + 1; d[n] = 0; 20 rep(i, 0, n - 1) scanf("%d %d ", x + i, y + i), u[i] = m + 1, d[i] = 0; 21 22 23 rep(i, 1, q){ 24 scanf("%d %d %d ", &xn, &ln, &rn); 25 u[xn] = rn; 26 d[xn] = ln; 27 } 28 29 rep(i, 0, n + 2) rep(j, 0, m + 2) dp[i][j] = INF; 30 31 rep(i, 1, m) dp[0][i] = 0; 32 rep(i, 1, n){ 33 rep(j, x[i - 1], m){ 34 dp[i][j] = min(dp[i][j], dp[i - 1][j - x[i - 1]] + 1); 35 dp[i][j] = min(dp[i][j], dp[i][j - x[i - 1]] + 1); 36 } 37 38 rep(j, m - x[i - 1], m){ 39 dp[i][m] = min(dp[i][m], dp[i - 1][j] + 1); 40 dp[i][m] = min(dp[i][m], dp[i][j] + 1); 41 } 42 43 rep(j, d[i] + 1, u[i] - 1){ 44 if (j + y[i - 1] <= m) dp[i][j] = min(dp[i][j], dp[i - 1][j + y[i - 1]]); 45 } 46 47 rep(j, 1, d[i]) dp[i][j] = INF; 48 rep(j, u[i], m) dp[i][j] = INF; 49 } 50 51 ans = INF; 52 rep(i, 1, m) ans = min(ans, dp[n][i]); 53 if (ans != INF) return 0, printf("%d\n%d\n", 1, ans); 54 int t = q; 55 dec(i, n, 1){ 56 rep(j, 1, m) ans = min(ans, dp[i][j]); 57 if (ans != INF) break; 58 if (u[i] != m + 1) --t; 59 } 60 61 printf("%d\n%d\n", 0, t); 62 return 0; 63 }