CF510D Fox And Jumping

题目链接

题目

见链接。

题解

方法一

知识点:背包dp,STL。

题目意思是让我们判断能否从这些数中选出一些数使得选的数公共gcd为 \(1\),如果可以输出最小花费。

一眼背包dp,但要map超大背包优化,因为数字很大 \(10^9\) ,显然无法直接在第二维放下。

\(dp[i][j]\) 表示考虑到第 \(i\) 个数,所有数的gcd为 \(j\) 的情况。 因为用map优化了,没法填表了,因为每行都的元素都不确定,应该用刷表法,用这一行结果推到下一行。转移方程为:

\[\begin{aligned} dp[i][x] &= \min(dp[i-1][x],dp[i][x])\\ dp[i][gcd(l[i],x)] &= \min(dp[i-1][x] + c[i],dp[i][gcd(l[i],x)]) \end{aligned} \]

前者表示不选第 \(i\) 个数的转移,后者表示选了第 \(i\) 个数的转移。

因为不能 memset 初始化正无穷,因此要做到循环中对第一次出现的状态初始化。同时,这也是解决数组太大每次全部初始化很费时间情况下的一种技巧。

注意为了方便,初始化了 \(dp[0][0] = 0\) 。用于每次选一个数自己是第一个数的情况,能正确被标记而不用特判,即 \(gcd(l[i],0) = l[i]\)。因为在我们写的gcd函数里, \(0\) 可以当作特殊的单位元,特殊之处在于其应该出现在函数的后面一个位置,即 \(gcd(a,0)\) ,否则会出错。

时间复杂度 \(O(n*玄学)\) ,qwq最大公约数种类不知道怎么算

空间复杂度 \(O(玄学)\)

方法二

知识点:BFS,优先队列,记忆化搜索。

说白了就是记忆化搜索,用广搜做最短路,求花费最小的路径,因此用优先队列。细节处理比dp少一点,而且差不多。

时间复杂度 \(O(能过而且更快)\)

空间复杂度 \(O(能过)\)

代码

方法一

///满足最优子结构,顺序上没有后效性可以dp
#include <bits/stdc++.h>

using namespace std;

int l[307], c[307];
unordered_map<int, int> dp[307];

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> l[i];
    for (int i = 1;i <= n;i++) cin >> c[i];
    dp[0][0] = 0;///gcd单位元
    for (int i = 1;i <= n;i++) {
        for (auto [x, y] : dp[i - 1]) {///向后传递,不能写找前继承
            if (!dp[i].count(x)) dp[i][x] = 0x3f3f3f3f;
            dp[i][x] = min(dp[i][x], y);
            int d = gcd(l[i], x);
            if (!dp[i].count(d)) dp[i][d] = 0x3f3f3f3f;
            dp[i][d] = min(dp[i][d], y + c[i]);
        }
    }
    if (dp[n].count(1)) cout << dp[n][1] << '\n';
    else cout << -1 << '\n';
    return 0;
}

方法二

///也可以写成优先队列bfs,好处是不用考虑后效性,以花费从小到大为顺序扩展,复杂度玄学
#include <bits/stdc++.h>

using namespace std;

int n;
int l[307], c[307];
unordered_set<int> vis;
struct node {
    int l;
    int c;
    friend bool operator<(const node &a, const node &b) {
        return a.c > b.c;
    }
};

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

int bfs() {
    priority_queue<node> pq;
    pq.push({ 0,0 });
    while (!pq.empty()) {
        node cur = pq.top();
        pq.pop();
        if (cur.l == 1) return cur.c;
        if (vis.count(cur.l)) continue;
        vis.insert(cur.l);///经过后再锁
        for (int i = 1;i <= n;i++) {
            int d = gcd(l[i], cur.l);
            if (vis.count(d)) continue;
            pq.push({ d,cur.c + c[i] });
        }
    }
    return -1;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> l[i];
    for (int i = 1;i <= n;i++) cin >> c[i];
    cout << bfs() << '\n';
    return 0;
}
posted @ 2022-08-12 23:51  空白菌  阅读(40)  评论(0编辑  收藏  举报