D. Bananas in a Microwave dp + 思维

D. Bananas in a Microwave dp + 思维

题目大意:

一开始 \(k = 0\) ,然后你有两种操作:

  • \(Type1:t_i=1,x_i,y_i\) ,选择一个 \(a_i\) ,满足 \(0\leq a_i\leq y_i\) ,然后对 \(k\) 进行下列操作 \(a_i\) 次,\(k = \left \lceil (k+x_i)\right \rceil\)
  • \(Type2:t_i=2,x_i,y_i\) 选择一个 \(a_i\) ,满足 \(0\leq a_i\leq y_i\) ,然后对 \(k\) 进行下列操作 \(a_i\) 次,\(k = \left \lceil (k*x_i) \right \rceil\)

注意:\(x_i\) 是一个浮点数

问:经过最少多少次操作,最后 \(k\) 会变成 \(j(1\leq j\leq m)\) ,输出步数最少的次数,如果不能,那么输出 -1

题解:

这个题目还是满巧妙的,很好的一个思维题。

  • 首先,很容易可以想到一个 \(O(N*M^2)\) 这个复杂度的方法。
  • 但是,显然这个复杂度太高了,是因为每一个点的访问次数有 \(N*M\)
  • 那么如果减少访问次数呢?
  • 如果: \(t,x,y=1,5,10\)\(k=10\) ,那么接下来 \(k = 15,20,...,55,60\) ,假设 40之前以及被访问过,那么还需要访问40吗?
  • 其实是不需要的,因为 \(40\) 被访问过,那么他的操作一定在这个之前,暂时还没有被访问,那么 \(40\) 之后一定会进行 \(t,x,y=1,5,10\) 这个操作,那么 \(k = 40,45,...,90\) ,所以连带着,上面40之后的所有数都不需要重新访问了。
  • 这样的话,其实每一个数最多只会被访问 \(N\)
  • 因为每次产生的新的数都会被保留下来,继续访问,如果访问到一个之前已经存下来的数,就不需要保留,因为之前往后转移时会覆盖这个结果。

最后感觉好像没有说的太明白,可以仔细看看 \(CF\) 的题解,非常好的一个题目,题解的代码也写的非常的漂亮。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int base = 1e5;
typedef long long ll;

typedef pair<int,int>pii;
queue<pii>que;

struct node{
    ll x;
    int t,y;
}e[maxn];

int ans[maxn];
bool is_seen[maxn];

inline ll Ceil(ll x,ll y){
    return (x + y - 1) / y;
}

auto cal(int t,ll &val,ll x) {
    if (t == 1) val += Ceil(x,base);
    else val = Ceil(val*x,base);
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; i++) scanf("%d%lld%d", &e[i].t, &e[i].x, &e[i].y);

    memset(ans, -1, sizeof(ans));
    ans[0] = 0;
    is_seen[0] = true;

    que.push(pii(0, 0));

    while (!que.empty()) {
        auto k = que.front().first;
        auto time = que.front().second;

        que.pop(), time++;

        if (time > n) break;

        auto t = e[time].t;
        auto x = e[time].x;
        auto y = e[time].y;

        ll val = k;
        for (int i = 1; i <= y; i++) {
            cal(t, val, x);

            if (val > m) break;
            if (is_seen[val]) break;

            is_seen[val] = true;
            ans[val] = time;
            que.push(pii(val, time));
        }
        que.push(pii(k, time));
    }
    for (int i = 1; i <= m; i++) printf("%d ", ans[i]);
    printf("\n");
}
posted @ 2021-04-01 16:16  EchoZQN  阅读(81)  评论(0编辑  收藏  举报