【CSP202112-2】序列查询新解

本文讲解了一种通过分析函数f(x)和区间长度A[i]-A[i-1]的关系,将问题转化为等差数列求和的方法。博主详细介绍了如何计算区间内的g(x)组数,以及如何处理最后不足一组的误差,最终给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



一、题目

在这里插入图片描述

二、解题思路

通过f(x)的取值可以看到,A[i]-A[i-1]的区间中f(x)值都一样,共有n+1个这样的区间,在每个区间里g可以看作每r个一组的等差数列,所以可以通过遍历1~n+1来做这道题。

	 for(long long i=1;i<=n;i++){
	   cin>>A[i];	   
	   B[i]=A[i]-A[i-1];//区间长度
	 }  
	 B[n+1]=N-A[n];

使用等差数列求和的话,要保证r个g(x)相等的一组,所以每个区间对r整除和取模,剩下的几个数拿去和下一个数组的前面几个数凑一组(他们的g(x)相等)。然后将每个区间完整的g(x)组求和。:

long long Sum(long long first,long long count){//首项,项数
	long long last =first+count-1;//末项
	long long final;
	//因为是绝对值求和,所以可能会有两段等差数列
	if(last*first>=0)//同符号  
       return final=abs((first+last)*count/2*r);
	else//不同符号,first是负数 
	   return final=(abs(first)+1)*abs(first)/2*r+last*(last+1)/2*r; 
} 
	 for(long long i=1;i<=n+1;i++){
	    //每段区间的f(x)的值是i-1
	 	Count=(B[i]+Sur)/r;//完整的g(x)组数
	 	g=A[i-1]/r;//第一个g(x)的值
	 	Error+=Sum(g-i+1,Count);

然后还要考虑一个问题,每个区间最后几个数本应该和当前f(x)做减法的,但是为了凑组,他们是和f(x)+1做了减法。

	 	if(g-i+1>=0)  Error+=Sur;//上一个组的后Sur个数的error值少加了1
	 	else         Error-=Sur;
	 	Sur=(B[i]+Sur)%r;//更新Sur值
	 }

再加上最后一个区间的最后几个凑不够一组的g(x)的error值就好了。

	 g+=Count;//更新g值
	 Error+=abs(g-n)*Sur;//最后一个区间x值为n
	 cout<<Error;

三、完整代码

#include <bits/stdc++.h>
using namespace std;
const long long Maxn=1e5+5;
long long A[Maxn]={0};
long long B[Maxn]={0};
long long r;
long long Sum(long long first,long long count){
	long long last =first+count-1;//末项
	long long final;
	if(last*first>=0)//同符号  
       return final=abs((first+last)*count/2*r);
	else//不同符号,first是负数 
	   return final=(abs(first)+1)*abs(first)/2*r+last*(last+1)/2*r; 
} 
int main(){
	 long long n,N;
	 long long Sur=0,Count,g;
	 long long Error=0;
	 cin>>n>>N;
	 r=N/(n+1);
	 for(long long i=1;i<=n;i++){
	   cin>>A[i];	   
	   B[i]=A[i]-A[i-1];//区间长度
	 }  
	 B[n+1]=N-A[n];
	 for(long long i=1;i<=n+1;i++){
	 	Count=(B[i]+Sur)/r;
	 	g=A[i-1]/r;
	 	Error+=Sum(g-i+1,Count);
	 	if(g-i+1>=0)  Error+=Sur;
	 	else         Error-=Sur;
	 	Sur=(B[i]+Sur)%r;
	 }
	 g+=Count;
	 Error+=abs(g-n)*Sur;
	 cout<<Error;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值