给出一个A数组,A = 【0,2,5,8】,n = 3,N = 10,r = 2;
在样例中可以看出在【0,2),【2,5),【5,8),【8,10)这些区间内,我们处在其中任何一个区间中时,f(i)就是已知的,并且相同。
我们假设一个函数absGfSum(a1, a2, f)表示在【a1,a2)区间内,已知f(i),求g(i)
我们知道在【a1,a2)中,f(i) 是不变的,而g(i)是单调递增的。
所以
1、 当g(a1) >= f 时,表示所有的g(i)都大于等于f(i),直接算出在【a1,a2)中abs( f(i)的总和 - g(i) 的总和);
2、当g(a2) <= f 时,表示所有的g(i)都小于等于f(i),也可以直接算出在【a1,a2)中abs( f(i)的总和 - g(i) 的总和);
3、当以上两个条件不满足时,说明前半段g(i) < f(i) 后半段g(i) >= f(i),那么只要算出中间 g(i) = f(i) 时的位置就行了,假设中间这个位置表示为mid,那么【a1,mid)就是第2种情况,【mid,a2) 就是第一种情况。
综上所述,我们还有两个问题需要解决。
第一个问题:计算【a1,a2)区间内,g(i) 的总和。
我们只需实现一个g(i)前n项和的函数gn,然后gn(a2 - 1)- gn(a1 - 1)即可。
当r = 2时,g(i)是0,0,1,1,2,2,3,3……
当r = 3时,g(i)是0,0,0,1,1,1,2,2,2,3,3,3……
以r = 2为例,将第一项和第二项,第三项和第四项依此类推,相加之后,就形成了一个等差数列。
等差数列an = (首项 + 尾项) * 项数 / 2;
编号:0,1,2,3,4,5,6,7,8……n
g(i) :0,0,1,1,2,2,3,3,4……n / r
相加后:0,2,4,6,8……
通过观察可以发现:g(i) = i / r;
(1)当(i + 1) / r == 0时,说明前 i 项 正好构成 像(0,0,1,1)这样整齐的数列
这时,首项为0, 尾项为 i / r * r (i / r 是g(i),相加后的尾项是 r 个g(i)),
项数为(i + 1)/ r,
(2)当(i + 1)/ r != 0时,我们先算出前i项中 像(0,0,1,1)这样整齐的数列,再加上多出的几项即可。
这时,首项为0,尾项为(i / r - 1) * r,项数为(i + 1) / r,还剩下(n + 1) % r项,所以最后加上(n + 1)% r * (n / r);
第二个问题:找到【a1, a2)区间内f(i) == g(i) 时的位置mid
直接遍历
long long mid = a1;
for(; mid <= a2; mid++){
if(mid / r == f){
break;
}
}
以上就是这道题的解题思路。
需要注意的是数据类型使用long long
下面是我的代码
#include <bits/stdc++.h>
using namespace std;
//计算g(i) 的前n项和
long long gn(long long n, long long r){
if(n < 0) return 0;
if((n + 1) % r != 0){
long long m = (n + 1) % r;
return (n / r * r - r) * ((n + 1) / r) / 2 + m * (n / r);
}
return n / r * r * ((n + 1) / r) / 2;
}
//计算在a1~a2范围内,当f(i)>g(i)时,f(i) - g(i)求和,当f(i)<=g(i)时,g(i) - f(i)求和
long long absGfSum(long long a1, long long a2, long long f, long long r){
if(a1 / r >= f || a2 / r <= f){
return abs((a2 - a1) * f - (gn(a2 - 1, r) - gn(a1 - 1, r)));
}
long long mid = a1;
for(; mid <= a2; mid++){
if(mid / r == f){
break;
}
}
return (mid - a1) * f - (gn(mid - 1, r) - gn(a1 - 1, r))
+ gn(a2 - 1, r) - gn(mid - 1, r) - (a2 - mid) * f;
}
int main(){
long long n, N;
cin >> n >> N;
long long r = N / (n + 1);
//记录数组中的前后两个数,数组中第一个数默认是0,所以a1作为数组中的第一个数,输入的数作为a2,
long long a1 = 0, a2 = 0;
long long sum = 0;
for(int j = 0; j < n; j++){
cin >> a2;
//j就是[a1, a2)范围内的f(i)的值
sum += absGfSum(a1, a2, j, r);;
a1 = a2;
}
a2 = N;
sum += absGfSum(a1, a2, n, r);
cout << sum << endl;
return 0;
}