两道关于序列变换(把无规则的序列变成有规则的序列)的好题

最近对于序列变换这类题的解法有一种心得,想分享给大家。

给大家三个题,其实是两个题,后两个题是一样的。把两个题放在一起,这样可以让你对这类题目有更深刻的理解。

牛客练习赛16 - B题:漂亮的树

题目链接:点这儿

这个题是要把序列变成这个形式:a, a + 1, a + 2, ...a + n / 2, a + n / 2 - 1, ... a + 1, a

如果,给出的序列本身就是这种形式,那么,把两个序列相减,就会得到b, b, ..., b,也就是得到一串相同的数字,那么再想一下,如果这个序列只有一个位置不符合规则,把两个序列相减就会得到b, b, ..., c, b, ..., b,那么这个序列中就只有有一个数字与众不同;

因此得出结论,把两个序列相减,相同数字最多的那些位置是不需要变动的,只需要把那些不相同的数字的位置的值变成符合条件就行了。

这样子,我们不仅得到了最少需要改变的数量,而且还得到了具体需要改变的位置。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (int n; EOF != scanf("%d", &n); ) {
        vector<int> arr(n);
        for (int i = 0; i < n; scanf("%d", &arr[i++])) {}
        map<int, int> mp;
        for (int i = 0; i < n / 2; ++mp[arr[i] - i - 1], ++i) {}
        for (int i = n - 1; i >= n / 2; ++mp[arr[i] - n + i], --i) {}
        struct cmp {
            bool operator () (const pair<int, int> &A, const pair<int, int> &B) const {
                return B.second > A.second;
            }
        };
        printf("%d\n", n - max_element(mp.begin(), mp.end(), cmp())->second);
    }
    return 0;
}

最长上升子序列

HDU5256 - 序列变换

题目链接:点这儿

这一题和上一题差不多,都是把最少改动转化成最多不需要改动。

和上一题一样的分析方法,要把序列变成严格递增的,这里我们手动构造一组严格递增序列:0, 1, 2, ..., n,而如果我们的序列就是严格递增的,把目标序列减去这个递增序列,看下差值序列,可以发现,差值序列也一定是递增的,只不过这个差值序列可能是非严格递增的;

而差值序列非严格递增的部分是不需要我们去改动的,因此,这题就是要求差值序列的最长不下降子序列的长度。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int T, K = 0, n;
    for (scanf("%d", &T); T--; ) {
        scanf("%d", &n);
        vector<int> arr;
        int ans = 0;
        for (int i = 0, x; i < n; scanf("%d", &x), arr.push_back(x - i++)) {}
        vector<int> dp;
        for (auto it = arr.begin(); it != arr.end(); ++it) {
            auto it2 = upper_bound(dp.begin(), dp.end(), *it);
            if (it2 == dp.end())
                dp.push_back(*it);
            else
                *it2 = *it;
        }
        printf("Case #%d:\n%d\n", ++K, ans + arr.size() - dp.size());
    }
    return 0;
}

51NOD1294 - 修改数组

题目链接:点这儿

和上一个题一样,只不过多了个条件:序列是正整数。上一个题没这个要求。

我们分析下,假设有一个序列:2, 3, 2, 2,那么后面两个数字一定要改掉,因为就算这个序列最后变成1, 2, 3, 4,原序列中的2 < 32 < 4,也就是说当一个序列中的一些数字不符合条件(arr[i] - i <= 0)一定要改掉时,我们就把这些数字从序列中剔除掉,剩下的数字构成的序列就运用上一题的方法做就行了。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (int n; EOF != scanf("%d", &n); ) {
        vector<int> arr;
        int ans = 0;
        for (int i = 0, x; i < n; i++) {
            scanf("%d", &x);
            if (x - i > 0)
                arr.push_back(x - i);
            else
                ++ans;
        }
        vector<int> dp;
        for (auto it = arr.begin(); it != arr.end(); ++it) {
            auto it2 = upper_bound(dp.begin(), dp.end(), *it);
            if (it2 == dp.end())
                dp.push_back(*it);
            else
                *it2 = *it;
        }
        printf("%d\n", ans + arr.size() - dp.size());
    }
    return 0;
}

总结

一定要把目标序列和当前序列放在一起看一下,最好做个差值,就可以找到之中的一些规律:把最少改动转化成最多不需要改动

猜你喜欢

转载自blog.csdn.net/FlushHip/article/details/80114894