• 每日构造/DP(4.25)


    D. Cyclic Rotation

    听说很多人赛时都被这道题卡了。。感觉并不难想啊。。

    逆向思考,原题意相当于如果存在 \(b[i] = b[i-1]\) ,则 \(b[i]\) 可以放在前方任意一个位置,然后这题就做完了。。

    具体做法的话先统计 \(b\) 数组中哪些数可以放前排去,然后开双指针,如果 \(l\)\(r\) 指向的当前位匹配不上,就把刚刚统计的数中与 \(a[l]\) 相匹配且位置靠前的数放在 \(r\) 指向的位置,可以证明这样的贪心是正确的。。然后如果出现某个位置既不匹配又没数可放就寄了。。

    #include <bits/stdc++.h>
    #define IOS                           \
        std::ios::sync_with_stdio(false); \
        std::cin.tie(0);                  \
        std::cout.tie(0);
    
    bool solve()
    {
        int n;
        std::cin >> n;
        std::vector<int> a(n + 1), b(n + 1), vis(n + 1);
        for (int i = 1; i <= n; ++i)
            std::cin >> a[i];
        for (int i = 1; i <= n; ++i)
            std::cin >> b[i];
        std::queue<int> q[n + 1];
        for (int i = 1; i <= n; ++i)
            if (b[i] == b[i - 1])
                q[b[i]].push(i);
        int l = 1, r = 1, delta = 0; // delta记录从后面拿了多少个数放前面,每放一个,后面的数相当于往后挪了一位
        while (l <= n && r <= n)
        {
            while (vis[r])
                ++r;
            if (a[l] == b[r])
                vis[r] = 1, ++l, ++r;
            else
            {
                if (q[a[l]].empty())
                    return false;
                int now = q[a[l]].front();
                while (vis[now])
                {
                    q[a[l]].pop();
                    if (q[a[l]].empty())
                        return false;
                    now = q[a[l]].front();
                }
                if (now + delta > l)
                {
                    vis[now] = 1;
                    ++l, ++delta;
                }
                else
                    return false;
            }
        }
        return true;
    }
    
    int main()
    {
        IOS;
        int t;
        std::cin >> t;
        while (t--)
            std::cout << (solve() ? "YES" : "NO") << std::endl;
        return 0;
    }
    

    E - RLE

    \(f[i][j]\) 表示 \(|S| = i,|T| = j\) 的方案数,有转移方程:

    \(f[i+k][j+c(k)+1] += 25*f[i][j]\)\(c(k)\) 表示数字 \(k\) 的位数

    复杂度为 \(O(n^3)\) ,考虑优化,由于 \(f[i][j]\) 对相同位数的 \(k\) 作的贡献是相同的,因此想到区间加

    区间加可以用什么实现呢?差分、前缀和、树状数组等等均可。这里用的是差分, \(d[i][j] = f[i][j] - f[i-1][j]\)

    #include <bits/stdc++.h>
    #define IOS                           \
        std::ios::sync_with_stdio(false); \
        std::cin.tie(0);                  \
        std::cout.tie(0);
    using ll = long long;
    
    int main()
    {
        IOS;
        int n, p;
        std::cin >> n >> p;
        std::vector<std::vector<ll>> f(n + 1, std::vector<ll>(n + 1));
        std::vector<std::vector<ll>> d(n + 2, std::vector<ll>(n + 1));
        auto calc = [&](int x)
        {
            int res = 1;
            while (x)
                x /= 10, ++res;
            return res;
        };
        std::vector<int> ten = {0, 1, 10, 100, 1000, 10000};
        std::vector<int> len(n + 1);
        for (int i = 1; i <= n; ++i)
            len[i] = calc(i);
        for (int i = 1; i <= n; ++i)
            d[i][len[i]] += 26, d[i + 1][len[i]] -= 26;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = len[i]; j <= n; ++j)
            {
                f[i][j] = (d[i][j] + f[i - 1][j]) % p;
                for (int k = 1; i + ten[k] <= n && j + k + 1 <= n; ++k)
                {
                    d[i + ten[k]][j + k + 1] = (d[i + ten[k]][j + k + 1] + 25 * f[i][j]) % p;
                    if (i + ten[k + 1] <= n)
                        d[i + ten[k + 1]][j + k + 1] = ((d[i + ten[k + 1]][j + k + 1] - 25 * f[i][j]) % p + p) % p;
                }
            }
        }
        ll ans = 0;
        for (int i = 1; i < n; ++i)
            ans = (ans + f[n][i]) % p;
        std::cout << ans;
        return 0;
    }
    
  • 相关阅读:
    小程序canvas生成海报-新旧接口
    vue网页小程序实现七牛云图片文件上传以及原生组件video显示不出问题
    【文化课】 一篇魔改英语理解
    python萌新笔记
    版本控制(Version control)
    开源许可证(License)
    agc004c
    python日期时间、时间戳互相转换
    拓展django-haystack全文检索的样式和搜索频率限制
    常用JS代码
  • 原文地址:https://www.cnblogs.com/Foreign/p/16196864.html
Copyright © 2020-2023  润新知