CCF CSP 202112-2 序列查询新解
试题编号: 202112-2
试题名称: 序列查询新解
时间限制: 1.0s
内存限制: 512.0MB
题目背景
题目描述
输入格式
输出格式
样例1输入:
3 10
2 5 8
样例1输出:
5
样例1解释:
样例2输入:
9 10
1 2 3 4 5 6 7 8 9
样例2输出:
0
样例3输入:
2 10
1 3
样例3输出:
6
样例3解释:
解题思路:
挨个挨个计算肯定会超时,根据第一题的思路,我们按照数组A中的数进行划分段,此时该段fi的和很容易计算,就是(i-1)*(a[i]-a[i-1])。
然后我们只需要计算此时的gi和,计算两者差值就可以得到error。
此时gi就是一个公差为1的等差数列,我们很容易得到其和,但是两边需要判断一下余数,即多加进去gi的数值。
但是,当当前的i-1在left和right中间时,计算差值相减会出现问题,比如:
fi为1,1,2,2,3,3
gi为2,2,2,2,2,2
此时的error为4,但是按照上面的计算方法却为0,此时我们只需要分段计算一下二者和即可
注意:题目数值较大,都需要用longlong
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
ll a[N];
ll cal_sn(ll a1,ll an) {
ll n=an-a1+1;
return n*(a1+an)/2;
}
int main()
{
ios::sync_with_stdio(false);
ll n,N;
cin>>n>>N;
for(int i=1;i<=n;++i)
cin>>a[i];
a[0]=0;
a[n+1]=N;
ll r=N/(n+1);
ll ans=0;
for(int i=1;i<=n+1;++i) {
ll left=a[i-1]/r,right=(a[i]-1)/r;
if(left>=i-1 || right<=i-1) {
ll original=(i-1)*(a[i]-a[i-1]);
ll sum=cal_sn(left,right)*r;
sum-=(a[i-1]%r)*left;
sum-=(r-((a[i]-1)%r)-1)*right;
ans+=abs(original-sum);
}
else {
ll mid=i*r;
ll original=(i-1)*(mid-a[i-1]);
ll sum=cal_sn(left,(mid-1)/r)*r;
sum-=(a[i-1]%r)*left;
sum-=(r-((mid-1)%r)-1)*((mid-1)/r);
ans+=abs(original-sum);
original=(i-1)*(a[i]-mid);
sum=cal_sn(mid/r,right)*r;
sum-=(mid%r)*mid/r;
sum-=(r-((a[i]-1)%r)-1)*right;
ans+=abs(original-sum);
}
}
cout<<ans<<endl;
return 0;
}