CCF-CSP 202112-2序列查询新解 详细解析

3 篇文章 0 订阅


CCF考试系统传送门

CCF-CSP计算机认证考试 202112-2 序列查询新解
CCF计算机软件能力认证考试系统


前言

最近刷题的时候遇到了这题,感觉逐步推理最终得出正解的过程挺不错的。现在来分享一下我的分析过程。


序列查询新解

1.题目内容

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解分析

一开始想用循环+二分的,复杂度为O(NlogN),而N是 1 0 9 10^9 109,肯定会超时。于是我们着眼于n,规模为 1 0 5 10^5 105,可以允许O(nlogn)左右的复杂度。这也就意味着,我们需要对A数组按区间进行处理。

接下来,寻找一个突破口。在前一题202112-1序列查询中,我是这样计算f(x)的和的:

a[n+1]=N;
for(int i=0;i<=n;i++)
	ans+=i*(a[i+1]-a[i]);

区间[a[i],a[i+1]-1]内,f(x)=i,所以尝试对区间内进行处理。观察题目中样例解释部分,f(x)和g(x)的分布是不同的,为保证各部分|f(x)-g(x)|等于总和,意味着我们需要对区间进行划分。观察g(x)具有以下规律:按相同值对g(x)划分区间,则g(x)中区间是连续的且每个区间长度为r,区间之间的值按1递增。为什么是1?首先g(x)= ⌊ x r ⌋ \lfloor{\frac{x}{r}}\rfloor rx,向下取整,其次r的最小值为1。

上述特性表示为:

对 x ∈ [ m r , ( m + 1 ) r − 1 ] , g ( x ) = m = ⌊ x r ⌋ 对x\in[mr,(m+1)r-1],g(x)=m=\lfloor{\frac{x}{r}}\rfloor x[mr,(m+1)r1]g(x)=m=rx

该特性的作用在于当我们知道了x,就可以求出x所在区间的左端或者右端点。因此我们可以在区间[a[i],a[i+1]-1]内按g(x)的值进行再次划分,求各子区间的|f(x)-g(x)|,再分别求和。

如何分割区间?对于每次for循环[a[i],a[i+1]-1],我们可以视为此时 x ∈ [ a [ i ] , a [ i + 1 ] − 1 ] x\in[a[i],a[i+1]-1] x[a[i],a[i+1]1],而f(x)=i,先设置一个值start存储左端点a[i],利用g(a[i])算出x在第一个子区间的函数值v,然后代入上面推的公式,(v+1)r-1即为第一个子区间的右端end,为防止end超过区间范围,使end=min((v+1)r-1,a[i+1]-1),所以(end-start)+1为子区间长度,v-i为子区间的值。所以对每个子区间有

∣ g ( x ) − f ( x ) ∣ = ∣ [ ( e n d − s t a r t ) + 1 ] ∗ ( v − i ) ∣ |g(x)-f(x)| = | [(end-start)+1]*(v-i) | g(x)f(x)=[(endstart)+1](vi)

对这个公式累加即可。为了能连续划分,需要使用while循环,每次循环开始前,使start=end+1,end到了右端点则跳出。

ll start,end=a[i]-1;
while(end<a[i+1]-1)
{
	start=end+1;
	ll v=start/r;
	end=min((v+1)*r-1,a[i+1]-1);
	ans+=abs((((end-start)+1)*(v-i)));
}

另外,变量类型需要使用long long,第一次提交因为没注意只拿了70分,改了就过了。

3.完整代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_N=1e5+10;
ll n,N,ans;
ll a[MAX_N];
int main()
{
	scanf("%lld%lld",&n,&N);
	ll r=N/(n+1);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	a[n+1]=N;
	for(int i=0;i<=n;i++)
	{
		ll start,end=a[i]-1;
		while(end<a[i+1]-1)
		{
			start=end+1;
			ll v=start/r;
			end=min((v+1)*r-1,a[i+1]-1);
			ans+=abs((((end-start)+1)*(v-i)));
		}
	}
	printf("%lld",ans);
	return 0;
}

评测结果
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值