A. Desorting
题意
给一个数列,每次操作可以把前一部分每个数加1,后一部分每个数减1,问至少操作多少次可以让数列非递增
思路
先遍历每一个数,如果有逆序的直接输出0
否则找到相邻元素最小的差值,最少的操作次数就是让这个最小的差值的两个元素变成逆序,除以2加1即可
代码
#include <bits/stdc++.h>
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 <bits/stdc++.h>
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<bits/stdc++.h>
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();
}