CCF 202112-2 序列查询新解 python 满分

本文详细解析了一道关于序列查询的竞赛题目,探讨了Python解答时的超时问题以及满分策略。作者首先介绍了题目的输入输出格式,并通过样例分析了解题思路。关键点包括计算g(x)的前n项和、判断转折点以及处理转折点后的计算。文中提供了两种Python代码实现,一种导致超时,另一种实现了满分优化。文章还引用了相关参考博文以供深入学习。

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

题目叙述

问题描述:略

输入格式:略

输出格式:略

样例

样例1输入
3 10
2 5 8

样例1输出
5

样例2输入
9 10
1 2 3 4 5 6 7 8 9

样例2输出
0

样例3输入
2 10
1 3

样例3输出
6


补充样例4输入
3 6
1 3 5

补充样例4输出
6

补充样例5输入
5 9
1 2 5 6 7

补充样例5输出
12

满分证明

在这里插入图片描述

解题思路

说实话,这题我做了好久才自己码出答案,确实有太多需要注意的地方。
听我室友讲现在CCF将Python运行时间和C++运行时间的评分标准调整了,也就是说同样的逻辑因为C++用的是底层代码所以运行速度更快,可以拿满分;但因为Python是再开发语言,运行速度慢,不能拿满分,这也解释了为什么第一题同样逻辑只有C++可以拿满分。
言归正传,在默认第一题拿到满分的情况下做第二题(第一题 CCF 202112-1 序列查询 python 满分),明白了需要分段的思路,第二题才有可能有思路。

01Python超时70分

01代码的思路很简单,优先创建两个数组,然后使用一次遍历就可以;这个代码中理论上应该把代码中的1e7 + 5换成1e9 + 5。如果使用C++语言,就可以得到满分(似乎之前看到有博主写了,所以这里我就不贴C++代码了)。但是如果你这里使用的Python,使用1e9 + 5会显示超时0分,直到你改为1e7 + 5,所以如果想用Pytho得满分就得进行优化。

在这里插入图片描述

02满分python思路

其实我和大佬满分思路一样(哈哈哈,准确说是我“借鉴”的大佬的参考博文1)。细心的看官应该注意到我在测试样例中多给出两个测试样例,正是因为这两个测试样例才让我的代码进一步修改为满分。
刚开始我只注意到在f(x)区间上分段,计算给定i(索引)下前g(x)的和,然后f(x)段和减去下面g(x)的和就可以了;事实上是我想太少了。因为在同样f(x)段下依然不能简单的减去g(x)的分段和;比如

f(x)111
g(x)012
|g(x)-f(x)|101
如果按之前的思路,则计算结果为0,但实际结果为2;
这里里面涉及到的就是如果在同一段f(x)下,如果g(x)都小于f(x)或都大于f(x)的话可以直接相减,但如果有“转折点”的话就要再分情况计算了。所以这道题我认为有三个难点。

第一,计算前n项g(x)的和

这里我们可以看作是r(N//(n+1))个首项为0,公差为1的等差数列;等差数列求和公式Sn=n*a1+n(n-1)d/2或Sn=n(a1+an)/2,这里不过多赘述自己推导即可(r个完整的等差数列求和再加最后几个不完整的);如果还不太懂可以看参考博文2,我最后推导完后事前i项和:

    x = (i + 1) // r
    sum_g = (x * (x - 1) * r / 2) + ((i + 1) % r) * x

第二,判断是否存在转折点条件

这里要判断要么区间内值全小于等于f(i),要么区间内值全大于等于f(i),这里f(i)实际就是i-1;这里等于放不放没影响,递增函数,同时满足这两个条件,有点像做高中数学函数恒成立问题;这里也不过多赘述。

第三,判断完转折点后如何

如果没有转折点,直接f(x)区间和减g(x)区间和;如果有转折点,找出转折点,从转折点处分段求。

具体实现见代码部分,为了更好地让大家理解题意和使用测试样例,我将所有样例的f(x), g(x), |f(x)-g(x)|均以列表的形式展示给大家,方便大家自检。

样例详细描述

样例1描述

n=3 N=10 r=2 out=5

i0123456789
f(i)0011122233
g(i)0011223344
|g(i)-f(i)|0000101111

样例2描述

n=2 N=10 r=3 out=6

i0123456789
f(i)0112222222
g(i)0001112223
|g(i)-f(i)|0111110001

样例3描述

n=2 N=10 r=2 out=5

i0123456789
f(i)0011111112
g(i)0001112223
|g(i)-f(i)|0010001111

补充样例4描述

n=3 N=6 r=1 out=6

i012345
f(i)011223
g(i)012345
|g(i)-f(i)|001122

补充样例5描述

n=5 N=9 r=1 out=12

i012345678
f(i)012223455
g(i)012345678
|g(i)-f(i)|000122223

具体实现代码

01Python超时70分代码

n, N = map(int, input().split())
ori_li = list(map(int, input().split()))

f = [0 for _ in range(int(1e7 + 5))]
dif = [0 for _ in range(int(1e7 + 5))]
for i in ori_li:
    dif[i] = dif[i] + 1

sum_f = 0
index = 1
fx = 0
r = (N // (n + 1))
for i in range(1, N):
    f[i] = f[i - 1] + dif[i]
    sum_f += abs(f[i] - (i // r))

print(sum_f)

02我的Python满分代码

n, N = map(int, input().split())
ori_li = list(map(int, input().split()))
ori_li.insert(0, 0)
sum_ = 0
r = (N // (n + 1))

# 计算g(x)分段和
def dif(id_f, id_s, r):
    id_fx = (id_f + 1) // r
    id_sx = (id_s + 1) // r
    sum_gs = (id_sx * (id_sx - 1) * r / 2) + ((id_s + 1) % r) * id_sx
    sum_gf = (id_fx * (id_fx - 1) * r / 2) + ((id_f + 1) % r) * id_fx
    return sum_gs - sum_gf


for i in range(1, n + 1):
    sum_f = (ori_li[i] - ori_li[i - 1]) * (i - 1)
    id_f = ori_li[i - 1] - 1
    id_s = ori_li[i] - 1

    if ((id_s // r) > (i - 1)) and ((id_f // r) < (i - 1)):
        id_m = i * r - 1
        sum_gf = dif(id_f, id_m, r)
        sum_ = sum_ + abs(sum_f - (i - 1) * (id_s - id_m) - sum_gf)
        sum_gs = dif(id_m, id_s, r)
        sum_ = sum_ + abs(sum_f - (i - 1) * (id_m - id_f) - sum_gs)
    else:
        sum_g = dif(id_f, id_s, r)
        sum_ = sum_ + abs(sum_f - sum_g)

# 处理结尾
if ori_li[-1] <= N - 1:
    sum_f = (N - ori_li[-1]) * n
    id_s = N - 1
    id_f = ori_li[-1] - 1

    if ((id_s // r) > n) and ((id_f // r) < n):
        id_m = n * r + 1
        sum_gf = dif(id_f, id_m, r)
        sum_gs = dif(id_m, id_s, r)
        sum_ = sum_ + abs(sum_f - n * (id_s - id_m) - sum_gf)
        sum_ = sum_ + abs(sum_f - n * (id_m - id_f) - sum_gs)
    else:
        sum_g = dif(id_f, id_s, r)
        sum_ = sum_ + abs(sum_f - sum_g)

print(int(sum_))

03大佬Python满分代码

n, N = tuple(map(int, input().split()))
# 有用的点
A = [0] + [int(x) for x in input().split()]


# 计算gi数列下标到x的和
def h(x):
    if x <= 0:
        return 0
    global r
    x = x + 1
    n = x // r
    m = x % r
    return int(n * (r * (n - 1) / 2 + m))


# 对下标为left到right的abs(fi-gi)求和,包括left和right两点
def cal(fi, left, right):
    return abs(h(right) - h(left - 1) - fi * (right - left + 1))


# 判断是否有转折点,并返回error增加量
def ischange(fi, left, right):
    # 没有转折点
    if left // r >= fi or right // r <= fi:
        return cal(fi, left, right);
    # 出现转折点
    else:
        # 算出第一个转折点
        splitindex = left + r * (fi - (left + 1) // r) + r - (left + 1) % r
        return cal(fi, left, splitindex) + ischange(fi, splitindex + 1, right)


r = N // (n + 1)
error = 0

# 根据fi的数值来分组,开始遍历
for fi in range(n + 1):
    left = A[fi]
    if fi < n:
        right = A[fi + 1] - 1
    else:
        right = N - 1
    error += ischange(fi, left, right)

print(error)

感谢及参考博文

部分内容参考以下链接,这里表示感谢 Thanks♪(・ω・)ノ
参考博文1 序列查询新解(python满分解法)
https://blog.youkuaiyun.com/qq_47780707/article/details/123262314
参考博文2 CCF CSP 202112-2 序列查询新解
https://blog.youkuaiyun.com/reidpa/article/details/121942425
参考博文3 202112(第24次)CSP真题202112-1,2讲解
https://www.bilibili.com/video/BV1v34y117Vi
参考博文4 【CCF-CSP】202112-2-序列查询新解100分(读过必懂)
https://blog.youkuaiyun.com/qq_21471309/article/details/123296864

需者自取传送门(∩ᄑ_ᄑ)⊃━☆【CCF 2013-2021】本博主整理历年至少前两题 python 满分代码目录

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值