Good Bye 2021: 2022 is NEAR

A - Integer Diversity

题目大意

给定一个数组, 每次可以选择任意长度的字串取反, 问最后能有多少不同的数字

思路

很简单, 用set记录每一个值是否出现过, 没有就插入, 有就取反然后插入

代码

#include <iostream>
#include <set>
 
using namespace std;
 
int main() {
    int T;
    cin >> T;
    while (T --) {
        int n;
        cin >> n;
        set<int> s;
        while (n --) {
            int x;
            cin >> x;
            if (s.count(x)) s.insert(-x);
            else s.insert(x);
        }
        cout << s.size() << endl;
    }
    return 0;
}

B - Mirror in the String

题目大意

给定一个字符串, 找一个前缀, 使其前缀和前缀反串的字典序最小

思路

首先, 选择的前缀一定是不增的
但是如果开始有两个以上的相同字符, 那么必然是取一个就好
否则, 依次向后查找, 直到遇到第一个更大的字符

代码

#include <iostream>
#include <set>
#include <algorithm>
 
using namespace std;
 
int main() {
    int T;
    cin >> T;
    while (T --) {
        int n;
        cin >> n;
        string str;
        cin >> str;
        if (n == 1 || str[0] == str[1]) cout << str[0] << str[0] << endl;
        else {
            int i = 0;
            while (i < str.length() && str[i + 1] <= str[i]) i ++;
            string a = str.substr(0, i + 1);
            cout << a;
            reverse(a.begin(), a.end());
            cout << a << endl;
        }
    }
    return 0;
}

C - Representative Edges

题目大意

给定一个长度为n的数组, 问最少需要改变多少数字, 可以使任意的l < r满足 \(a_l + a_{l + 1} + \ldots + a_r = \frac{1}{2}(a_l + a_r) \cdot (r - l + 1)\)

思路

是在看过样例之后发现, 最后的结果总是变为一个等差数列
开始想, 是否可以枚举起点公差, 但是存在精度问题
于是, n是很小的, 直接三重枚举, 判断在ij之间有多少k满足 \((a_k - a_i) \cdot (k - j) == (a_k - a_j) \cdot (k - i)\)
当然也要化除为乘

代码

#include <iostream>
#include <set>
#include <algorithm>
 
using namespace std;
 
int n;
int a[100];
 
int main() {
    int T;
    cin >> T;
    while (T --) {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> a[i];
 
        int ans = 1;
        for (int i = 1; i <= n; i ++)
            for (int j = i + 1; j <= n; j ++) {
                int cnt = 0;
                for (int k = 1; k <= n; k ++)
                    if (k == i || k == j || (a[k] - a[i]) * (k - j) == (a[k] - a[j]) * (k - i))
                        cnt ++;
                ans = max(ans, cnt);
            }
        cout << n - ans << endl;
    }
    return 0;
}

D - Keep the Average High

题目大意

给定一个长度为n的数组, 在其中选择最多的下标使得, 任意l < r满足

  • 区间内至少有一个数没有被选择
  • 或者, 总和大于 长度 * X

思路

不知道为什么就想到DP了
定义一个数组f[N][2], 表示到当前位置, 当前位置选或不选的最大结果数
状态转移好像有些不清晰了
/*

  • 首先当前位置不选的话
  • 上一个位置选和不选都可以, 取最大值
  • 当前位置选
  • 上一个位置不选是可以的
  • 写了几次发现, 当前位置只会和前两个位置产生转移, 再前面就不会影响了
  • 转移的条件必然是和上一个位置的和大于2 * X
  • 如果当前位置大于X, 那么上一个位置就是可选的, 这里为什么不讨论上二个是因为 选上一个已经讨论过是否选上二个了
  • 如果是上一个位置大于X, 那么必须注意这三个位置的和是否也是大于3 * X
  • 这里首先是可以从上二个不选转移
  • 然后就是大于3 * X的话, 上二个也是可以被选择的
    这里有个技巧是多判断一个, 然后答案直接取多判断那个不取的情况
    */

代码

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;

const int N = 5e4 + 10;

int n, x;
int a[N];
int f[N][2];

int main() {
    int T;
    cin >> T;
    while (T --) {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> a[i];
        cin >> x;

        f[1][0] = 0, f[1][1] = 1;
        for (int i = 2; i <= n + 1; i ++) {
            f[i][0] = max(f[i - 1][0], f[i - 1][1]);
            f[i][1] = f[i - 1][0] + 1;
            if (a[i] >= x && a[i] + a[i - 1] >= 2 * x) f[i][1] = max(f[i][1], f[i - 1][1] + 1);
            else {
                if (a[i - 1] >= x && a[i] + a[i - 1] >= 2 * x) {
                    if (i == 2) f[i][1] = 2;
                    else {
                        f[i][1] = max(f[i][1], f[i - 2][0] + 2);
                        if (a[i - 2] + a[i - 1] >= 2 * x && a[i - 2] + a[i - 1] + a[i] >= 3 * x)
                            f[i][1] = max(f[i][1], f[i - 2][1] + 2);
                    }
                }
            }
        }
        cout << f[n + 1][0] << endl;
    }
    return 0;
}
posted @ 2022-01-02 11:12  哇唔?  阅读(73)  评论(0编辑  收藏  举报