每日构造/DP(4.22)

E. Magic Stones

难点主要在想到用差分做。。

\(d\)\(c\) 的差分数组,由 \(c′_i = c_{i+1} + c_{i−1} − c_i\) 移项可得: \(c′_i + c_{i−1} = c_{i+1} − c_i\)

因此对 \(c_i\) 进行一次操作相当于交换 \(d_i\)\(d_{i+1}\) ,故将 \(c\)\(t\) 的差分数组排序后判断是否相同即可。

#include <bits/stdc++.h>
#define IOS                           \
    std::ios::sync_with_stdio(false); \
    std::cin.tie(0);                  \
    std::cout.tie(0);
#define PLL std::pair<ll, ll>
#define val first
#define id second
using ll = long long;

int main()
{
    IOS;
    int n;
    std::cin >> n;
    std::vector<ll> c(n + 1), t(n + 1), a(n + 1), b(n + 1);
    for (int i = 1; i <= n; ++i)
        std::cin >> c[i];
    for (int i = 1; i <= n; ++i)
        std::cin >> t[i];
    for (int i = 1; i <= n; ++i)
        a[i] = c[i] - c[i - 1], b[i] = t[i] - t[i - 1];
    std::sort(a.begin() + 1, a.begin() + n + 1);
    std::sort(b.begin() + 1, b.begin() + n + 1);
    bool flag = true;
    for (int i = 1; i <= n; ++i)
        flag &= a[i] == b[i];
    if (c[1] != t[1] || c[n] != t[n])
        flag = false;
    std::cout << (flag ? "Yes" : "No") << std::endl;
    return 0;
}

P1941 飞扬的小鸟

\(f[i][j]\) 表示前 \(i\) 秒,高度为 \(j\) ,点击的最少次数,有转移方程:

\(f[i][j] = \underset {1 \leq k \leq \lfloor \frac{j}{x_i} \rfloor}{min}\{f[i - 1][j - k * x_i] + k,f[i - 1][j + y_i]\}\) ,复杂度为 \(O(n^3)\) ,考虑优化

不难发现上升与下降状态本质上就是完全背包 + 01背包,因此对于上升状态有新的转移方程:

\[f[i][j] = min \begin{cases} f[i - 1][j - x_i]& 在~i - 1~秒点击~1~次上升到~j\\ f[i][j - x_i]& 在~i - 1~秒点击~k~次上升到~j - x_i~,再点击~1~次到~j \end{cases} + 1\]

除此之外细节也还蛮多的。。

#include <bits/stdc++.h>
#define IOS                           \
    std::ios::sync_with_stdio(false); \
    std::cin.tie(0);                  \
    std::cout.tie(0);
const int inf = 0x3f3f3f3f;

int main()
{
    IOS;
    int n, m, k;
    std::cin >> n >> m >> k;
    std::vector<int> x(n + 1), y(n + 1), l(n + 1), h(n + 1), v(n + 1);
    for (int i = 1; i <= n; ++i)
        std::cin >> x[i] >> y[i];
    for (int i = 1; i <= n; ++i)
        l[i] = 1, h[i] = m;
    for (int i = 1, p; i <= k; ++i)
    {
        std::cin >> p;
        std::cin >> l[p] >> h[p];
        ++l[p], --h[p], v[p] = 1;
    }
    std::vector<std::vector<int>> f(n + 1, std::vector<int>(m + 1, inf));
    for (int i = 0; i <= m; ++i)
        f[0][i] = 0;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
            if (j > x[i])
                f[i][j] = std::min(f[i][j], std::min(f[i - 1][j - x[i]], f[i][j - x[i]]) + 1);
        for (int j = m - x[i]; j <= m; ++j) // 从 m - x[i] ~ m 开始点,最多到 m
            f[i][m] = std::min(f[i][m], std::min(f[i - 1][j], f[i][j]) + 1);
        for (int j = 1; j <= m; ++j)
            if (j + y[i] <= m)
                f[i][j] = std::min(f[i][j], f[i - 1][j + y[i]]);
        for (int j = 1; j <= l[i] - 1; ++j)
            f[i][j] = inf;
        for (int j = h[i] + 1; j <= m; ++j)
            f[i][j] = inf;
    }
    int min = inf;
    for (int i = n, now = k; i; now -= v[i--])
    {
        for (int j = m; j; --j)
            min = std::min(min, f[i][j]);
        if (min < inf)
        {
            if (i == n)
            {
                std::cout << 1 << std::endl;
                std::cout << min << std::endl;
                return 0;
            }
            else
            {
                std::cout << 0 << std::endl;
                std::cout << now << std::endl;
                return 0;
            }
        }
    }
    std::cout << "0\n0";
    return 0;
}
posted @ 2022-04-22 12:56  FoXreign  阅读(18)  评论(0编辑  收藏  举报