【NOIP2014】飞扬的小鸟

本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1941


 

怎么会有这么迷的一道题!

明明思路很简单,但要想A掉,细节怎么就不好想呢!

很显然的DP,状态一目了然,处理好特殊情况,一步步推就可以了。

DP有刷表法和填表法,为了推的过程中特判是否到最高处省事,我选择了刷表法,80分,TLE了四个点,需要优化。超时主要是在于转移上,一个状态近似可以转移到m个状态,优化是当发现某次无法取得更优解,就剪枝,因为再往下肯定不会更优。而且需要从m到1枚举,可能这样会剪去更多的枝,好玄。。。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 inline int get_num() {
 8     int num = 0;
 9     char c = getchar();
10     while (c < '0' || c > '9') c = getchar();
11     while (c >= '0' && c <= '9')
12         num = num * 10 + c - '0', c = getchar();
13     return num;
14 }
15 
16 const int maxn = 1e4 + 5, maxm = 1e3 + 5, inf = 0x3f3f3f3f;
17 
18 int tube[2][maxn], updown[2][maxn], dp[maxn][maxm];
19 //0为下,1为上
20 
21 int main() {
22     int n, m, k, ans = inf, cnta = 0, cntb = 0;
23     n = get_num(), m = get_num(), k = get_num();
24     for (int i = 0; i < n; ++i)
25         updown[1][i] = get_num(), updown[0][i] = get_num();
26     memset(tube[1], inf, sizeof(tube[1]));
27     for (int i = 1; i <= k; ++i) {
28         int p = get_num(), l = get_num(), h = get_num();
29         tube[0][p] = l, tube[1][p] = h;
30     }
31     memset(dp, inf, sizeof(dp));
32     memset(dp[0], 0, sizeof(dp[0]));
33     for (int i = 0; i <= n; ++i)
34         for (int j = m; j >= 0; --j) {
35             if (dp[i][j] == inf) continue;
36             if (i == n) {ans = min(ans, dp[i][j]); continue;}
37             cnta = max(cnta, i);
38             int next = j - updown[0][i], cnt;
39             if (next > tube[0][i + 1] && next < tube[1][i + 1])
40                 dp[i + 1][next] = min(dp[i + 1][next], dp[i][j]);
41             next = j + updown[1][i], cnt = 1;
42             if (next > m) next = m;
43             while (next <= m) {
44                 if (dp[i][j] + cnt > dp[i + 1][next]) break;
45                 if (next > tube[0][i + 1] && next < tube[1][i + 1])
46                     dp[i + 1][next] = min(dp[i + 1][next], dp[i][j] + cnt);
47                 if (next == m) break;
48                 next += updown[1][i], ++cnt;
49                 if (next > m) next = m;
50             }
51         }
52     if (ans < inf) printf("1\n%d", ans);
53     else {
54         for (int i = 0; i <= cnta; ++i)
55             if (tube[1][i] < inf) ++cntb;
56         printf("0\n%d", cntb);
57     }
58     return 0;
59 }
AC代码

 

posted @ 2018-10-23 10:49  Mr^Kevin  阅读(415)  评论(0编辑  收藏  举报