【cf】CodeForces Round 887(Div.2)题解 A - C

A. Desorting

题意

给一个数列,每次操作可以把前一部分每个数加1,后一部分每个数减1,问至少操作多少次可以让数列非递增

思路

先遍历每一个数,如果有逆序的直接输出0

否则找到相邻元素最小的差值,最少的操作次数就是让这个最小的差值的两个元素变成逆序,除以2加1即可

代码

#include 

using namespace std;

int main()
{
    int t; cin >> t;
    while (t -- )
    {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i ++ ) cin >> a[i];
        int l, r, minn = 0x3f3f3f3f;
        bool flag = true;
        for (int i = 1; i < n; i ++ )
        {
            if (a[i] < a[i - 1])
            {
                cout << 0 << endl;
                flag = false;
                break;
            }
            if (a[i] - a[i - 1] < minn)
            {
                minn = a[i] - a[i - 1];
                l = i - 1, r = i;
            }
        }
        int ans = minn / 2 + 1;
        if (flag) cout << ans << endl;
    }
}

B. Fibonaccharsis

题意

给定斐波那契数列的第 k 项是 n,问存在多少这样的数列

思路

设第一个数是 x,第二个数是 y
那么第三个数 x + y ,第四个数x + 2 * y,第五个数2 * x + 3 * y
可以推出,x 的系数是 0 1 1 2 3 5 …,y 的系数是 1 1 2 3 5 8…
现有斐波那契数列(下标从1开始) 0 1 1 2 3 5 8…
那么 x 的系数 a 就是 fib[i - 1] y 的系数 b 就是fib[i]
于是问题转换成了a * x + b * y = n,求xy有多少种取值情况,要求xy均为整数且 x <= y,对 x 逐项枚举即可

代码

#include 

using namespace std;

int main()
{
    int t;
    cin >> t;
    vector<int> fib(31);
    function<void(void)> init = [&](void)
    {
        fib[1] = 0, fib[2] = 1;
        for (int i = 3; i <= 30; i ++ )
            fib[i] = fib[i - 1] + fib[i - 2];
    };
    init();
    while (t -- )
    {
        int n, k;
        cin >> n >> k;
        if (k > 30)
        {
            cout << "0\n";
            continue;
        }
        int x, y;
        int a, b;
        int ans = 0;
        a = fib[k - 1], b = fib[k];
        for (x = 0; x <= n / 2; x ++ )
            if ((n - (a * x)) % b == 0 && (n - (a * x)) / b >= x) ans ++ ;
        cout << ans << '\n';
    }
}

C. Ntarsis’ Set

题意

有个从1开始逐渐递增的集合,每次操作给出任意个位数,删去给出位数上的数字,得到新数列,现给出操作次数和每次操作删去的位数,求操作完后的第一位是几

思路

从每一轮当前的第一位数字开始遍历,如果当前遍历到的这位数字位于a[i]a[i - 1]之间,那么它的前 i 个位置都会被删去

代码

#include

using namespace std;
using LL = long long;

const int N = 2e5 + 5;

LL a[N];

inline void solve() {
    LL n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) cin >> a[i];
    LL j = 0, ans = 1; // ans表示目前的第一位 j表示截至目前已经处理过的位数
    while (k--)
    {
        while (j < n && a[j] <= ans + j) j++;
        ans += j; // 更新该轮结束后的第一位,也就是该轮刚开始时的第一位加上该轮已处理过的位数
    }
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) solve();
}

你可能感兴趣的:(Codeforces,题解,算法)