CSP 202104-4 校门外的树 python 动态规划DP + 约数优化

简介: CSP 202104-4 校门外的树 python 动态规划DP + 约数优化

CSP 202104-4 校门外的树 python 动态规划DP + 约数优化


题目连接


题目描述


X 校最近打算美化一下校园环境。前段时间因为修地铁,X 校大门外种的行道树全部都被移走了。现在 X 校打算重新再种一些树,为校园增添一抹绿意。


X 校大门外的道路是东西走向的,我们可以将其看成一条数轴。在这条数轴上有 n 个障碍物,例如电线杆之类的。虽然障碍物会影响树的生长,但是障碍物不一定能被随便移走,所以 X 校规定在障碍物的位置上不能种树。n 个障碍物的坐标都是整数;如果规定向东为正方向,则 n 个障碍物的坐标按照从西到东的顺序分别为 a1,a2,⋯,an。X 校打算在 [a1,an] 之间种一些树,使得这些树看起来比较美观。


X 校希望,在一定范围内,树应该是等间隔的。更具体地说,如果把 [a1,an) 划分成一些区间 [ap1,ap2),⋯,[apm−1,apm)(1=p1<p2<⋯<pm=n),那么每个区间 [api,api+1) 内需要至少种一棵树,且该区间内种的树的坐标连同区间端点 api,api+1 应该构成一个等差数列。不同区间的公差,也就是树的间隔可以不相同。


例如,如果障碍物位于 0,2,6 这三处,那么我们可以选择在 [0,2) 和 [2,6) 分别种树,也可以选择在 [0,6) 等间隔种树。如果是分别在 [0,2) 和 [2,6) 种树,由于每个区间内至少要种一棵树,坐标 1 上必须种树;而 [2,6) 上的树可以按照 1 的间隔种下,也可以按照 2 的间隔种下。下图表示了这两种美观的种树方案,其中橙色的圆表示障碍物,绿色的圆表示需要在这个位置种树,箭头上的数字表示种下这棵树时对应的间隔为多少。


684c963e09efa3eef439d573b3e3f5e5.png


对区间 [0,2) 和 [2,6) 分别以 1 和 2 的间隔种树是美观的



caa0615708c910d5ba7542cca8927fac.png


对区间 [0, 2) 和 [2, 6) 分别以 1 的间隔种树也是美观的 而如果选择在 [0,6) 区间等间隔种树,我们只能以 3 的间隔种树,因为无论是选择间隔 1 或者间隔 2,都需要在坐标 2 上种树,而这个位置已经有障碍物了。下图分别表示了间隔为 3,2,1 时的种树情况,红色箭头表示不能在这里种树。


5740061932fb410a34663da8e8be7e90.png

对区间 [0, 6) 以 3 的间隔种树是美观的



4626675c4be3ab8af6ba4ef784e31cec.png


图 4: 对区间 [0, 6) 以 2 的间隔种树是不美观的



d6eaf29cf541c301ddf1bfcb5b955d2a.png


图 5: 对区间 [0, 6) 以 1 的间隔种树也是不美观的

一般地,给定一个区间 [al,ar),对于树的坐标的集合 T⊂(al,ar)(T⊂Z),归纳定义 T 在 [al,ar) 上是美观的:


如果 T≠∅,T∩{al,al+1,⋯,ar}=∅,并且存在一个公差 d≥1,使得 T∪{al,ar} 中的元素按照从小到大的顺序排序后,可以构成一个公差为 d 的等差数列(显然,这个等差数列的首项为 al,末项为 ar),则 T 在 [al,ar) 上是美观的;

如果 T∩{al,al+1,⋯,ar}=∅,并且存在一个下标 m(l<m<r),使得 T∩(al,am) 在 [al,am) 上是美观的,且 T∩(am,ar) 在 [am,ar) 上是美观的,则 T 在 [al,ar) 上是美观的。

根据这一定义,空集在任意区间上都不是美观的;另外,如果存在下标 i 使得 ai∈T,那么 T 一定不是美观的。


我们称两种种树的方案是本质不同的,当且仅当两种方案中,种树的坐标集合不同。请帮助 X 校对 [a1,an) 求出所有本质不同的美观的种树方案。当然,由于方案可能很多,你只需要输出总方案数对 10^9+7 取模的结果。


输出格式


输出到标准输出。

输出一个非负整数,表示本质不同的美观的种树方案的数量对 109+7 取模的结果。


样例输入1

3
0 2 6

样例输出1


3


样例说明1


这组样例即为题面描述中提到的那组。


样例输入2

11
0 10 20 30 40 50 60 70 80 90 10

样例输出2


256507


样例输入3


333
33 44 67 210 528 762 873 984 1234 1466 1739 2859 3421 4061 4598 5172 5201 5220 5261 532


样例输出3


7094396


思路


这道题需要用到动态规划DP,并且f[0]=1


设f [ i ] 为前i个障碍物所能生成的最多可能性

设  cnt[i][j]为从第i个障碍物到第j个障碍物的可行方案数

想要求cnt[i][j]只需从位置i枚举所有间隔的可能性, 看是否能在不触碰到 i , j 之间的障碍物的情况下到达


我们就可以写出我们的动态转移方程


image.png



比如我们求f[2]的时候,就是


image.png


动态规划的话只能够拿到60分,但是如果要拿满分,还需要进行约数优化的方法。


除此之外,得到我们的cnt数组的时候,第j个障碍物到第i个障碍物之间的方案数,注意这里是把a[j]和a[i]之间看作一个整体进行植树,不考虑分割情况,即在此区间里所有的树和a[j]、a[i]构成等差数列。如果只是穷举的话,我们就会超时,所以这里需要进行约数优化的方法。


约数优化:可以想到第j个障碍物到第i个障碍物之间 植树间隔 必须为 a [ i ] − a [ j ] 的 因子,方案数一定小于等于因子个数,因为这个间隔还不能撞上 a [ j ]和 a [ i ] 之间的障碍物。我们倒着从 i − 1  开始枚举 j ,这样一开始$ i - 1$ 和 $i 之 间 是 没 有 障 碍 物 的 , 则 之间是没有障碍物的,则之间是没有障碍物的,则a[i] - a[i - 1] 的 所 有 因 子 都 满 足 条 件 ; 然 后 到 了 ]的所有因子都满足条件;然后到了]的所有因子都满足条件;然后到了i - 2, 同 样 先 枚 举 ,同样先枚举,同样先枚举a[i] - a[i - 2]的 所 有 因 子 , 这 些 因 子 中 已 经 处 于 集 合 中 的 一 定 不 可 , 等 于 的所有因子,这些因子中已经处于集合中的一定不可,等于的所有因子,这些因子中已经处于集合中的一定不可,等于a[i]-a[i-1]的 也 不 可 , 因 为 按 这 样 的 间 隔 排 列 一 定 会 有 树 遇 上 的也不可,因为按这样的间隔排列一定会有树遇上的也不可,因为按这样的间隔排列一定会有树遇上a[i - 1]这 个 障 碍 物 ; 以 此 类 推 , 倒 着 枚 举 到 这个障碍物;以此类推,倒着枚举到这个障碍物;以此类推,倒着枚举到a[i] - a[k]因 子 的 时 候 , 如 果 已 经 在 之 前 的 枚 举 中 使 用 过 , 则 跳 过 , 否 则 方 案 数 就 加 一 。 我 们 使 用 一 个 状 态 数 组 因子的时候,如果已经在之前的枚举中使用过,则跳过,否则方案数就加一。我们使用一个状态数组因子的时候,如果已经在之前的枚举中使用过,则跳过,否则方案数就加一。我们使用一个状态数组st[M]$,保存某个因子是否已经使用过了,。


代码


60分 运行超时


第一个方法代码只能过60%,得到60分就运行超时了

# http://118.190.20.162/view.page?gpid=T125
n = int(input())
a = list(map(int,input().split()))
N = 1010
MOD = int(1e9+7)
def get_cnt(a,b):
    res = 0
    maxn = b - a
    for i in range(1,maxn+1): # 枚举间隔
        if a + i == b: continue
        for j in range(a+i,b+1,i): # 不断进行枚举
            if j > b: # 没有到达b
                break
            if j == b:
                res += 1
                break
            if st[j]:
                break
    return res
'''
设f[i]为前i个障碍物所能生成的最多可能性
设 cnt[i][j]为从第i个障碍物到第j个障碍物的可行方案数
想要求cnt[i][j]只需从位置i枚举所有间隔的可能性,看是否能在不触碰到i,j之间的障碍物的情况下到达
'''
f = [0]*N
f[0] = 1
cnt = [[0]*N for _ in range(N)]
from collections import defaultdict
st = defaultdict(int)
for i in range(n):
    st[a[i]] = 1
for i in range(n-1):
    for j in range(i+1,n):
        cnt[i][j] = get_cnt(a[i],a[j])%MOD
for i in range(1,n):
    for j in range(0,i):
        f[i] = (f[i] + f[j]*cnt[j][i]%MOD)%MOD
print(f[n-1])

动态规划DP + 约数优化

# http://118.190.20.162/view.page?gpid=T125
from collections import defaultdict
n = int(input())
a = list(map(int,input().split()))
N = 1010
MOD = int(1e9+7)
'''
设f[i]为前i个障碍物所能生成的最多可能性
设 cnt[i][j]为从第i个障碍物到第j个障碍物的可行方案数
想要求cnt[i][j]只需从位置i枚举所有间隔的可能性,看是否能在不触碰到i,j之间的障碍物的情况下到达
'''
f = [0]*N
f[0] = 1
q = defaultdict(list)
M = 100010
for i in range(1,M):
    for j in range(2*i,M,i):
        q[j].append(i)
# 动态规划
for i in range(1,n): # 每轮添加一个障碍物,计算添加后的方案总数
    st = defaultdict(int) # 清空状态数组
    for j in range(i-1,-1,-1):
        d = a[i] - a[j]
        cnt = 0
        for k in q[d]: # 枚举d的所有的因子,也就是所有可能的方案
            if not st[k]: # 如果此因子之前没使用过,方案数加一,并标记当前因子已被用过
                cnt += 1
                st[k] = 1
        # 手动添加d本身,因为下一轮如果按照这个间隔植树就会撞上本轮添加的障碍物
        st[d] = 1 # 因为最后一个障碍物必选
        f[i] = (f[i] + f[j]*cnt)%MOD
print(f[n-1])


相关文章
|
4天前
|
存储 缓存 算法
优化Python代码性能的7个技巧
在日常的Python开发中,优化代码性能是一个重要的课题。本文介绍了7个实用的技巧,帮助开发者提高Python代码的执行效率,包括利用生成器表达式、使用适量的缓存、避免不必要的循环等。通过本文的指导,读者可以更好地理解Python代码性能优化的方法,提升自身的编程水平。
|
4天前
|
算法 Java 编译器
优化Python代码性能的实用技巧
提高Python代码性能是每个开发者的关注焦点之一。本文将介绍一些实用的技巧和方法,帮助开发者优化他们的Python代码,提升程序的执行效率和性能。
|
4天前
|
机器学习/深度学习 数据采集 算法
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
|
4天前
|
数据采集 数据可视化 数据挖掘
利用Python和Pandas库优化数据分析流程
在当今数据驱动的时代,数据分析已成为企业和个人决策的重要依据。Python作为一种强大且易于上手的编程语言,配合Pandas这一功能丰富的数据处理库,极大地简化了数据分析的流程。本文将探讨如何利用Python和Pandas库进行高效的数据清洗、转换、聚合以及可视化,从而优化数据分析的流程,提高数据分析的效率和准确性。
|
4天前
|
SQL 数据采集 数据挖掘
构建高效的Python数据处理流水线:使用Pandas和NumPy优化数据分析任务
在数据科学和分析领域,Python一直是最受欢迎的编程语言之一。本文将介绍如何通过使用Pandas和NumPy库构建高效的数据处理流水线,从而加速数据分析任务的执行。我们将讨论如何优化数据加载、清洗、转换和分析的过程,以及如何利用这些库中的强大功能来提高代码的性能和可维护性。
|
4天前
|
缓存 数据库连接 数据库
构建高性能的Python Web应用:优化技巧与最佳实践
本文探讨了如何通过优化技巧和最佳实践来构建高性能的Python Web应用。从代码优化到服务器配置,我们将深入研究提高Python Web应用性能的各个方面。通过本文,读者将了解到一系列提高Python Web应用性能的方法,从而更好地应对高并发和大流量的挑战。
|
4天前
|
JSON 数据可视化 Shell
数据结构可视化 Graphviz在Python中的使用 [树的可视化]
数据结构可视化 Graphviz在Python中的使用 [树的可视化]
11 0
|
4天前
|
缓存 并行计算 Serverless
优化Python代码性能的5个技巧
在日常Python编程中,代码性能的优化是一个重要的议题。本文介绍了5个实用的技巧,帮助你提高Python代码的执行效率,包括使用适当的数据结构、优化循环结构、利用内置函数、使用生成器表达式以及并行化处理。通过这些技巧,你可以更高效地编写Python代码,提升程序的性能和响应速度。
|
4天前
|
机器学习/深度学习 数据采集 数据可视化
Python众筹项目结果预测:优化后的随机森林分类器可视化|数据代码分享
Python众筹项目结果预测:优化后的随机森林分类器可视化|数据代码分享
|
4天前
|
SQL 分布式计算 数据可视化
数据分享|Python、Spark SQL、MapReduce决策树、回归对车祸发生率影响因素可视化分析
数据分享|Python、Spark SQL、MapReduce决策树、回归对车祸发生率影响因素可视化分析