CSP-202112-2-序列查询新解
【70分思路】
- 【暴力枚举】按照题目思路遍历一遍f(x)和g(x),计算error(A),时间复杂度为O(N),时间超限。
#include <iostream>
using namespace std;
int main() {
long long n, N, sum = 0;
cin >> n >> N;
long long r = N / (n + 1);
long long* A = new long long[n + 1];
A[0] = 0;
for (int i = 1; i <= n; i++)
cin >> A[i];
// 初始化fx,gx
int ii = 1;
for (int i = 0; i < N; i++)
{
if (i == A[ii]) ii++;
// abs((ii - 1) - (i / r)): |f(x) - g(x)|
sum += abs((ii - 1) - (i / r));
}
cout << sum;
delete[] A;
return 0;
}
【100分思路】
- 【优化思路】结合第一问的提示,针对划分出的区间直接求解,似乎为该题的可行思路。
- f(x):求其在某个区间的和,可以直接借鉴第一题方法。在 x ∈ [ A [ i − 1 ] , A [ I ] ) x \in [A[i-1],A[I]) x∈[A[i−1],A[I]) 时,所有的 f(x) 都为 i − 1 i - 1 i−1。
- g(x):g(x) 在确定的 f(x) 恒等区间里,其未必全部相等。但由于向下取整的运算,g(x) 也存在区间恒等的性质。因此在 f(x) 与 g(x) 的恒等区间重合部分就可以进行直接求解。
MAX
是仍与当前 g(x) 相等的最大 x (j==x)值,以此可求得对应 g(x) 恒等区间的长度len
。注意 MAX 的运算是可能超出当前 j 的恒等区间的,要确保不超过当前区间的边界。len
是确保|f(j) - g(j)| != 0
的区间长度,并且在该区间内|f(j) - g(j)|
恒等,该区间内的error(A)可以直接通过(|f(j) - g(j)| * len
计算。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n, N, len, MAX = -1, A[100010] = {}; // MAX 仍与当前 g 相等的最大 j 值
long long errorA = 0;
cin >> n >> N;
for (int i = 1; i <= n; i++)
{
cin >> A[i];
}
A[n + 1] = N;
int r = N / (n + 1);
for (int i = 1; i <= n + 1; i++)
{
for (int j = A[i - 1]; j < A[i]; j += len)
{
int g = j / r; // j = x
// (g + 1) * r - 1 是 MAX 可能的最大值,确保不超过当前区间的边界
if ((g + 1) * r - 1 < A[i]) {
MAX = (g + 1) * r - 1;
}
else {
MAX = A[i] - 1;
}
len = MAX - j + 1;
errorA += (abs(i - 1 - g)) * len; // f(x) = i - 1
}
}
cout << errorA;
return 0;
}